Merge pull request #716 from AuthMe-Team/master

Sync with the development repository
This commit is contained in:
Gabriele C 2016-06-16 04:16:13 +02:00 committed by GitHub
commit 19d6179230
341 changed files with 12092 additions and 5611 deletions

View File

@ -3,7 +3,7 @@ sudo: false
language: java language: java
jdk: oraclejdk7 jdk: oraclejdk7
script: mvn verify -B script: mvn clean verify -B
notifications: notifications:
webhooks: webhooks:

260
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>fr.xephi</groupId> <groupId>fr.xephi</groupId>
<artifactId>authme</artifactId> <artifactId>authme</artifactId>
<version>5.2-BETA2</version> <version>5.2-BETA3</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>AuthMeReloaded</name> <name>AuthMeReloaded</name>
@ -21,9 +21,9 @@
</organization> </organization>
<scm> <scm>
<connection>scm:git:https://github.com/Xephi/AuthMeReloaded.git</connection> <connection>scm:git:https://github.com/AuthMe-Team/AuthMeReloaded.git</connection>
<developerConnection>scm:git:git@github.com:Xephi/AuthMeReloaded.git</developerConnection> <developerConnection>scm:git:git@github.com:AuthMe-Team/AuthMeReloaded.git</developerConnection>
<url>https://github.com/Xephi/AuthMeReloaded</url> <url>https://github.com/AuthMe-Team/AuthMeReloaded</url>
</scm> </scm>
<ciManagement> <ciManagement>
@ -49,22 +49,24 @@
</prerequisites> </prerequisites>
<properties> <properties>
<!-- Project Properties --> <!-- Project properties -->
<projectEncoding>UTF-8</projectEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>${projectEncoding}</project.build.sourceEncoding> <project.jdkVersion>1.7</project.jdkVersion>
<project.build.outputEncoding>${projectEncoding}</project.build.outputEncoding>
<jdkVersion>1.7</jdkVersion>
<testJreVersion>1.7</testJreVersion>
<!-- Output properties --> <!-- Output properties -->
<pluginName>AuthMe</pluginName> <project.outputName>AuthMe</project.outputName>
<jarName>${pluginName}-${project.version}</jarName> <project.buildNumber>CUSTOM</project.buildNumber>
<mainClass>${project.groupId}.${project.artifactId}.${pluginName}</mainClass> <project.skipExtendedHashTests>false</project.skipExtendedHashTests>
<pluginAuthors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu</pluginAuthors> <project.versionCode>${project.version}-b${project.buildNumber}</project.versionCode>
<buildNumber>Unknown</buildNumber> <project.finalName>${project.outputName}-${project.version}</project.finalName>
<!-- BukkitPlugin properties -->
<bukkitplugin.name>${project.outputName}</bukkitplugin.name>
<bukkitplugin.main>${project.groupId}.${project.artifactId}.${bukkitplugin.name}</bukkitplugin.main>
<bukkitplugin.authors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu</bukkitplugin.authors>
<!-- Change Bukkit Version HERE! --> <!-- Change Bukkit Version HERE! -->
<bukkitVersion>1.9.2-R0.1-SNAPSHOT</bukkitVersion> <bukkit.version>1.10-R0.1-SNAPSHOT</bukkit.version>
</properties> </properties>
<!-- Jenkins profile (add the real buildNumber to the version string) --> <!-- Jenkins profile (add the real buildNumber to the version string) -->
@ -77,47 +79,44 @@
</property> </property>
</activation> </activation>
<properties> <properties>
<buildNumber>${env.BUILD_NUMBER}</buildNumber> <project.buildNumber>${env.BUILD_NUMBER}</project.buildNumber>
</properties>
</profile>
<profile>
<id>skipLongHashTests</id>
<activation>
<property>
<name>skipLongHashTests</name>
</property>
</activation>
<properties>
<project.skipExtendedHashTests>true</project.skipExtendedHashTests>
</properties> </properties>
</profile> </profile>
</profiles> </profiles>
<build> <build>
<finalName>${jarName}-noshade</finalName> <!-- Name of the NOSHADE jar (no shaded/relocated libraries) -->
<sourceDirectory>src/main/java</sourceDirectory> <finalName>${project.finalName}-noshade</finalName>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources> <resources>
<resource> <resource>
<targetPath>.</targetPath>
<filtering>false</filtering>
<directory>.</directory> <directory>.</directory>
<filtering>false</filtering>
<includes> <includes>
<include>LICENSE</include> <include>LICENSE</include>
</includes> </includes>
</resource> </resource>
<resource> <resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory> <directory>src/main/resources/</directory>
<includes> <filtering>true</filtering>
<include>*</include>
</includes>
</resource> </resource>
<resource> <resource>
<directory>src/main/resources/messages/</directory>
<targetPath>./messages/</targetPath> <targetPath>./messages/</targetPath>
<filtering>false</filtering> <filtering>false</filtering>
<directory>src/main/resources/messages/</directory>
<includes>
<include>*.yml</include>
</includes>
</resource> </resource>
</resources> </resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins> <plugins>
<!-- Maven Java Compiler --> <!-- Maven Java Compiler -->
@ -126,10 +125,8 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.5.1</version>
<configuration> <configuration>
<source>${jdkVersion}</source> <source>${project.jdkVersion}</source>
<target>${jdkVersion}</target> <target>${project.jdkVersion}</target>
<testSource>${testJreVersion}</testSource>
<testTarget>${testJreVersion}</testTarget>
</configuration> </configuration>
</plugin> </plugin>
<!-- Test Plugin --> <!-- Test Plugin -->
@ -138,21 +135,30 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version> <version>2.19.1</version>
<configuration> <configuration>
<argLine>-Dfile.encoding=${projectEncoding} ${argLine}</argLine> <argLine>-Dfile.encoding=${project.build.sourceEncoding} @{argLine}</argLine>
<systemPropertyVariables>
<project.skipExtendedHashTests>${project.skipExtendedHashTests}</project.skipExtendedHashTests>
</systemPropertyVariables>
</configuration> </configuration>
</plugin> </plugin>
<!-- Libs Shading and Relocation --> <!-- Libs Shading and Relocation -->
<plugin> <plugin>
<!--Relocate all lib we use in order to fix class loading errors if we use different versions <!--
than already loaded libs (i.e. by Mojang -> gson)--> Relocate all lib we use in order to fix class loading errors if we use different versions
than already loaded libs (i.e. by Mojang -> gson)
-->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version> <version>2.4.3</version>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<!--
Let's try to remove this!
<minimizeJar>false</minimizeJar> <minimizeJar>false</minimizeJar>
-->
</configuration> </configuration>
<executions> <executions>
<!-- Spigot 1.8+ -->
<execution> <execution>
<id>spigot-shade</id> <id>spigot-shade</id>
<phase>package</phase> <phase>package</phase>
@ -160,6 +166,7 @@
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
<configuration> <configuration>
<!-- Exclude guava (already included into spigot) -->
<artifactSet> <artifactSet>
<excludes> <excludes>
<exclude>com.google.guava:guava</exclude> <exclude>com.google.guava:guava</exclude>
@ -187,15 +194,20 @@
<pattern>net.ricecode.similarity</pattern> <pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern> <shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
</relocation>
<!-- MCStats.org metrics --> <!-- MCStats.org metrics -->
<relocation> <relocation>
<pattern>org.mcstats</pattern> <pattern>org.mcstats</pattern>
<shadedPattern>fr.xephi.authme</shadedPattern> <shadedPattern>fr.xephi.authme</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
<outputFile>target/${jarName}-spigot.jar</outputFile> <outputFile>target/${project.finalName}-spigot.jar</outputFile>
</configuration> </configuration>
</execution> </execution>
<!-- 1.7.10 and lower -->
<execution> <execution>
<id>legacy-shade</id> <id>legacy-shade</id>
<phase>package</phase> <phase>package</phase>
@ -225,22 +237,41 @@
<pattern>net.ricecode.similarity</pattern> <pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern> <shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
</relocation>
<!-- MCStats.org metrics --> <!-- MCStats.org metrics -->
<relocation> <relocation>
<pattern>org.mcstats</pattern> <pattern>org.mcstats</pattern>
<shadedPattern>fr.xephi.authme</shadedPattern> <shadedPattern>fr.xephi.authme</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
<outputFile>target/${jarName}-legacy.jar</outputFile> <outputFile>target/${project.finalName}-legacy.jar</outputFile>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- Exec Tools -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<classpathScope>test</classpathScope>
<workingDirectory>${project.basedir}/target/test-classes</workingDirectory>
<mainClass>tools.ToolsRunner</mainClass>
<arguments>
<argument>updateDocs</argument>
</arguments>
<includeProjectDependencies>true</includeProjectDependencies>
</configuration>
</plugin>
<!-- Test coverage --> <!-- Test coverage -->
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version> <version>0.7.7.201606060606</version>
<executions> <executions>
<execution> <execution>
<id>prepare-agent</id> <id>prepare-agent</id>
@ -254,7 +285,7 @@
<plugin> <plugin>
<groupId>org.eluder.coveralls</groupId> <groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId> <artifactId>coveralls-maven-plugin</artifactId>
<version>4.1.0</version> <version>4.2.0</version>
<configuration> <configuration>
<failOnServiceError>false</failOnServiceError> <failOnServiceError>false</failOnServiceError>
</configuration> </configuration>
@ -264,11 +295,8 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version> <version>2.10.4</version>
<configuration> <configuration>
<charset>UTF-8</charset>
<docencoding>UTF-8</docencoding>
<docfilessubdirs>true</docfilessubdirs>
<show>public</show> <show>public</show>
<failOnError>false</failOnError> <failOnError>false</failOnError>
</configuration> </configuration>
@ -354,19 +382,6 @@
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- JDBC drivers for datasource integration tests -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
<scope>test</scope>
</dependency>
<!-- Log4J Logger (required by the console filter) --> <!-- Log4J Logger (required by the console filter) -->
<dependency> <dependency>
@ -375,7 +390,6 @@
<!-- Can't use newer versions due to api changes! --> <!-- Can't use newer versions due to api changes! -->
<version>2.0-beta9</version> <version>2.0-beta9</version>
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional>
</dependency> </dependency>
<!-- Java Email Library --> <!-- Java Email Library -->
@ -396,7 +410,7 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Guava (required to provide 1.7.10 and below compatibility) --> <!-- Guava (the version provided by the latest bukkit version) -->
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
@ -405,6 +419,15 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Inject API -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Maxmind GeoIp API --> <!-- Maxmind GeoIp API -->
<dependency> <dependency>
<groupId>com.maxmind.geoip</groupId> <groupId>com.maxmind.geoip</groupId>
@ -429,21 +452,12 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!--Spigot API--> <!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.9.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
<dependency> <dependency>
<groupId>org.bukkit</groupId> <groupId>org.spigotmc</groupId>
<artifactId>bukkit</artifactId> <artifactId>spigot-api</artifactId>
<version>${bukkitVersion}</version> <version>${bukkit.version}</version>
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
@ -465,6 +479,10 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
</exclusion> </exclusion>
<exclusion>
<artifactId>bungeecord-chat</artifactId>
<groupId>net.md-5</groupId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
@ -474,7 +492,6 @@
<artifactId>ProtocolLib</artifactId> <artifactId>ProtocolLib</artifactId>
<version>3.6.5-SNAPSHOT</version> <version>3.6.5-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>cglib-nodep</artifactId> <artifactId>cglib-nodep</artifactId>
@ -591,14 +608,13 @@
<artifactId>craftbukkit</artifactId> <artifactId>craftbukkit</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<optional>true</optional>
</dependency> </dependency>
<!-- Multi World plugin, http://www.spigotmc.org/resources/multiverse-core.390/ --> <!-- Multi World plugin, http://www.spigotmc.org/resources/multiverse-core.390/ -->
<dependency> <dependency>
<groupId>com.onarandombox.multiversecore</groupId> <groupId>com.onarandombox.multiversecore</groupId>
<artifactId>Multiverse-Core</artifactId> <artifactId>Multiverse-Core</artifactId>
<version>2.5</version> <version>2.5.0-SNAPSHOT</version>
<type>jar</type> <type>jar</type>
<scope>provided</scope> <scope>provided</scope>
<exclusions> <exclusions>
@ -646,8 +662,15 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<groupId>junit</groupId> <groupId>junit</groupId>
</exclusion> </exclusion>
<exclusion>
<artifactId>spigot-api</artifactId>
<groupId>org.spigotmc</groupId>
</exclusion>
<exclusion>
<artifactId>jettison</artifactId>
<groupId>org.codehaus.jettison</groupId>
</exclusion>
</exclusions> </exclusions>
<optional>true</optional>
</dependency> </dependency>
<!-- Essentials plugin --> <!-- Essentials plugin -->
@ -666,7 +689,6 @@
<artifactId>craftbukkit</artifactId> <artifactId>craftbukkit</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<optional>true</optional>
</dependency> </dependency>
<!-- Anti-PvPLogging plugin, https://github.com/MinelinkNetwork/CombatTagPlus --> <!-- Anti-PvPLogging plugin, https://github.com/MinelinkNetwork/CombatTagPlus -->
@ -741,7 +763,6 @@
<groupId>org.mcstats.bukkit</groupId> <groupId>org.mcstats.bukkit</groupId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<optional>true</optional>
</dependency> </dependency>
<!-- XAuth, another authentication plugin, required by the database converter --> <!-- XAuth, another authentication plugin, required by the database converter -->
@ -784,36 +805,6 @@
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
</exclusion> </exclusion>
</exclusions> </exclusions>
<optional>true</optional>
</dependency>
<!-- Unit Testing Libraries -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>4.12</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<scope>test</scope>
<version>2.0.0.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
<version>2.0.5-beta</version>
<optional>true</optional>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- String comparison library. Used for dynamic help system. --> <!-- String comparison library. Used for dynamic help system. -->
@ -824,5 +815,44 @@
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Unit Testing Libraries -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<scope>test</scope>
<version>2.0.0.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
<version>2.0.5-beta</version>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- JDBC drivers for datasource integration tests -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.192</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,126 @@
<?php
/*****************************************************************************
* AuthMe website integration logic *
* ------------------------------------------------------------------------- *
* Allows interaction with the AuthMe database (registration, password *
* verification). Don't forget to update the AUTHME_TABLE value and your *
* database credentials in getAuthmeMySqli(). *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
*****************************************************************************/
abstract class AuthMeController {
const AUTHME_TABLE = 'authme';
/**
* Entry point function to check supplied credentials against the AuthMe database.
*
* @param string $username the username
* @param string $password the password
* @return bool true iff the data is correct, false otherwise
*/
function checkPassword($username, $password) {
if (is_scalar($username) && is_scalar($password)) {
$hash = $this->getHashFromDatabase($username);
if ($hash) {
return $this->isValidPassword($password, $hash);
}
}
return false;
}
/**
* Returns whether the user exists in the database or not.
*
* @param string $username the username to check
* @return bool true if the user exists; false otherwise
*/
function isUserRegistered($username) {
$mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT 1 FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');
$stmt->bind_param('s', $username);
$stmt->execute();
return $stmt->fetch();
}
// Defensive default to true; we actually don't know
return true;
}
/**
* Registers a player with the given username.
*
* @param string $username the username to register
* @param string $password the password to associate to the user
* @return bool whether or not the registration was successful
*/
function register($username, $password) {
$mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) {
$hash = $this->hash($password);
$stmt = $mysqli->prepare('INSERT INTO ' . self::AUTHME_TABLE . ' (username, realname, password, ip) '
. 'VALUES (?, ?, ?, ?)');
$username_low = strtolower($username);
$stmt->bind_param('ssss', $username, $username_low, $hash, $_SERVER['REMOTE_ADDR']);
return $stmt->execute();
}
return false;
}
/**
* Hashes the given password.
*
* @param $password string the clear-text password to hash
* @return string the resulting hash
*/
protected abstract function hash($password);
/**
* Checks whether the given password matches the hash.
*
* @param $password string the clear-text password
* @param $hash string the password hash
* @return boolean true if the password matches, false otherwise
*/
protected abstract function isValidPassword($password, $hash);
/**
* Returns a connection to the database.
*
* @return mysqli|null the mysqli object or null upon error
*/
private function getAuthmeMySqli() {
// CHANGE YOUR DATABASE DETAILS HERE BELOW: host, user, password, database name
$mysqli = new mysqli('localhost', 'root', '', 'authme');
if (mysqli_connect_error()) {
printf('Could not connect to AuthMe database. Errno: %d, error: "%s"',
mysqli_connect_errno(), mysqli_connect_error());
return null;
}
return $mysqli;
}
/**
* Retrieves the hash associated with the given user from the database.
*
* @param string $username the username whose hash should be retrieved
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/
private function getHashFromDatabase($username) {
// Add here your database host, username, password and database name
$mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->bind_result($password);
if ($stmt->fetch()) {
return $password;
}
}
return null;
}
}

View File

@ -0,0 +1,20 @@
<?php
/***********************************************************
* AuthMe website integration logic for BCrypt *
* ------------------------------------------------------- *
* See AuthMeController for details. *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
***********************************************************/
class Bcrypt extends AuthMeController {
protected function hash($password) {
return password_hash($password, PASSWORD_BCRYPT);
}
protected function isValidPassword($password, $hash) {
return password_verify($password, $hash);
}
}

View File

@ -0,0 +1,48 @@
<?php
/***********************************************************
* AuthMe website integration logic for SHA256 *
* ------------------------------------------------------- *
* See AuthMeController for details. *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
***********************************************************/
class Sha256 extends AuthMeController {
/** @var string[] range of characters for salt generation */
private $CHARS;
const SALT_LENGTH = 16;
public function __construct() {
$this->CHARS = self::initRandomChars();
}
protected function isValidPassword($password, $hash) {
// $SHA$salt$hash, where hash := sha256(sha256(password) . salt)
$parts = explode('$', $hash);
return count($parts) === 4 && $parts[3] === hash('sha256', hash('sha256', $password) . $parts[2]);
}
protected function hash($password) {
$salt = $this->generateSalt();
return '$SHA$' . $salt . '$' . hash('sha256', hash('sha256', $password) . $salt);
}
/**
* @return string randomly generated salt
*/
private function generateSalt() {
$maxCharIndex = count($this->CHARS) - 1;
$salt = '';
for ($i = 0; $i < self::SALT_LENGTH; ++$i) {
$salt .= $this->CHARS[mt_rand(0, $maxCharIndex)];
}
return $salt;
}
private static function initRandomChars() {
return array_merge(range('0', '9'), range('a', 'f'));
}
}

View File

@ -1,107 +0,0 @@
<?php
/*****************************************************************************
* AuthMe website integration logic for BCrypt *
* -------------------------------- *
* Check with authme_check_password() whether the received username and *
* password match the AuthMe MySQL database. Don't forget to adjust the *
* database info in authme_get_hash(). *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
*****************************************************************************/
/** The name of the authme MySQL table. */
define('AUTHME_TABLE', 'authme');
/**
* Entry point function to check supplied credentials against the AuthMe database.
*
* @param string $username the username
* @param string $password the password
* @return bool true iff the data is correct, false otherwise
*/
function authme_check_password($username, $password) {
if (is_scalar($username) && is_scalar($password)) {
$hash = authme_get_hash($username);
if ($hash) {
return password_verify($password, $hash);
}
}
return false;
}
/**
* Returns a connection to the database.
*
* @return mysqli|null the mysqli object or null upon error
*/
function authme_get_mysqli() {
$mysqli = new mysqli('localhost', 'root', '', 'authme');
if (mysqli_connect_error()) {
printf('Could not connect to AuthMe database. Errno: %d, error: "%s"',
mysqli_connect_errno(), mysqli_connect_error());
return null;
}
return $mysqli;
}
/**
* Retrieves the hash associated with the given user from the database.
*
* @param string $username the username whose hash should be retrieved
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/
function authme_get_hash($username) {
// Add here your database host, username, password and database name
$mysqli = authme_get_mysqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT password FROM ' . AUTHME_TABLE . ' WHERE username = ?');
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->bind_result($password);
if ($stmt->fetch()) {
return $password;
}
}
return null;
}
/**
* Returns whether the user exists in the database or not.
*
* @param string $username the username to check
* @return bool true if the user exists; false otherwise
*/
function authme_has_user($username) {
$mysqli = authme_get_mysqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT 1 FROM ' . AUTHME_TABLE . ' WHERE username = ?');
$stmt->bind_param('s', $username);
$stmt->execute();
return $stmt->fetch();
}
// Defensive default to true; we actually don't know
return true;
}
/**
* Registers a player with the given username.
*
* @param string $username the username to register
* @param string $password the password to associate to the user
* @return bool whether or not the registration was successful
*/
function authme_register($username, $password) {
$mysqli = authme_get_mysqli();
if ($mysqli !== null) {
$hash = password_hash($password, PASSWORD_BCRYPT);
$stmt = $mysqli->prepare('INSERT INTO ' . AUTHME_TABLE . ' (username, realname, password, ip) '
. 'VALUES (?, ?, ?, ?)');
$username_low = strtolower($username);
$stmt->bind_param('ssss', $username, $username_low, $hash, $_SERVER['REMOTE_ADDR']);
return $stmt->execute();
}
return false;
}

View File

@ -1,6 +1,6 @@
<!-- <!--
This is a demo page for AuthMe website integration with BCrypt. This is a demo page for AuthMe website integration.
See integration.php for the PHP code you need. See AuthMeController.php and the extending classes for the PHP code you need.
--> -->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -12,17 +12,23 @@
<?php <?php
error_reporting(E_ALL); error_reporting(E_ALL);
require 'AuthMeController.php';
// Change this to the file of the hash encryption you need, e.g. Bcrypt.php or Sha256.php
require 'Sha256.php';
// The class name must correspond to the file you have in require above! e.g. require 'Sha256.php'; and new Sha256();
$authme_controller = new Sha256();
$action = get_from_post_or_empty('action'); $action = get_from_post_or_empty('action');
$user = get_from_post_or_empty('username'); $user = get_from_post_or_empty('username');
$pass = get_from_post_or_empty('password'); $pass = get_from_post_or_empty('password');
$was_successful = false; $was_successful = false;
if ($action && $user && $pass) { if ($action && $user && $pass) {
require_once('integration.php');
if ($action === 'Log in') { if ($action === 'Log in') {
$was_successful = process_login($user, $pass); $was_successful = process_login($user, $pass, $authme_controller);
} else if ($action === 'Register') { } else if ($action === 'Register') {
$was_successful = process_register($user, $pass); $was_successful = process_register($user, $pass, $authme_controller);
} }
} }
@ -50,11 +56,11 @@ function get_from_post_or_empty($index_name) {
// Login logic // Login logic
function process_login($user, $pass) { function process_login($user, $pass, AuthMeController $controller) {
if (authme_check_password($user, $pass)) { if ($controller->checkPassword($user, $pass)) {
printf('<h1>Hello, %s!</h1>', htmlspecialchars($user)); printf('<h1>Hello, %s!</h1>', htmlspecialchars($user));
echo 'Successful login. Nice to have you back!' echo 'Successful login. Nice to have you back!'
. '<br /><a href="form.php">Back to form</a>'; . '<br /><a href="index.php">Back to form</a>';
return true; return true;
} else { } else {
echo '<h1>Error</h1> Invalid username or password.'; echo '<h1>Error</h1> Invalid username or password.';
@ -63,15 +69,15 @@ function process_login($user, $pass) {
} }
// Register logic // Register logic
function process_register($user, $pass) { function process_register($user, $pass, AuthMeController $controller) {
if (authme_has_user($user)) { if ($controller->isUserRegistered($user)) {
echo '<h1>Error</h1> This user already exists.'; echo '<h1>Error</h1> This user already exists.';
} else { } else {
// Note that we don't validate the password or username at all in this demo... // Note that we don't validate the password or username at all in this demo...
$register_success = authme_register($user, $pass); $register_success = $controller->register($user, $pass);
if ($register_success) { if ($register_success) {
printf('<h1>Welcome, %s!</h1>Thanks for registering', htmlspecialchars($user)); printf('<h1>Welcome, %s!</h1>Thanks for registering', htmlspecialchars($user));
echo '<br /><a href="form.php">Back to form</a>'; echo '<br /><a href="index.php">Back to form</a>';
return true; return true;
} else { } else {
echo '<h1>Error</h1>Unfortunately, there was an error during the registration.'; echo '<h1>Error</h1>Unfortunately, there was an error during the registration.';

View File

@ -1,52 +0,0 @@
<!--
This is a demo page for AuthMe website integration with SHA256.
See integration.php for the PHP code you need.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>AuthMe Integration Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
error_reporting(E_ALL);
$user = get_from_post_or_empty('username');
$pass = get_from_post_or_empty('password');
$was_successful = false;
if ($user && $pass) {
require_once('integration.php');
if (authme_check_password($user, $pass)) {
printf('<h1>Hello, %s!</h1>', htmlspecialchars($user));
echo 'Successful login. Nice to have you back!'
. '<br /><a href="form.php">Back to form</a>';
$was_successful = true;
} else {
echo '<h1>Error</h1> Invalid username or password.';
}
}
if (!$was_successful) {
echo '<h1>Login sample</h1>
This is a demo form for AuthMe website integration. Enter your AuthMe login details
into the following form to test it.
<form method="post">
<table>
<tr><td>Name</td><td><input type="text" value="' . htmlspecialchars($user) . '" name="username" /></td></tr>
<tr><td>Pass</td><td><input type="password" value="' . htmlspecialchars($pass) . '" name="password" /></td></tr>
<tr><td colspan="2"><input type="submit" value=" Log in " /></td></tr>
</table>
</form>';
}
function get_from_post_or_empty($index_name) {
return trim(
filter_input(INPUT_POST, $index_name, FILTER_UNSAFE_RAW, FILTER_REQUIRE_SCALAR | FILTER_FLAG_STRIP_LOW)
?: '');
}
?>
</body>
</html>

View File

@ -1,67 +0,0 @@
<?php
/*****************************************************************************
* AuthMe website integration logic for SHA256 *
* -------------------------------- *
* Check with authme_check_password() whether the received username and *
* password match the AuthMe MySQL database. Don't forget to adjust the *
* database info in authme_get_hash(). *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
*****************************************************************************/
/**
* Entry point function to check supplied credentials against the AuthMe database.
*
* @param string $username the username
* @param string $password the password
* @return bool true iff the data is correct, false otherwise
*/
function authme_check_password($username, $password) {
if (is_scalar($username) && is_scalar($password)) {
$hash = authme_get_hash($username);
if ($hash) {
return authme_check_hash($password, $hash);
}
}
return false;
}
/**
* Retrieves the hash associated with the given user from the database.
*
* @param string $username the username whose hash should be retrieved
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/
function authme_get_hash($username) {
// Add here your database host, username, password and database name
$mysqli = new mysqli('HOST', 'USER', 'PWD', 'DB');
$authme_table = 'authme';
if (mysqli_connect_error()) {
printf('Could not connect to AuthMe database. Errno: %d, error: "%s"',
mysqli_connect_errno(), mysqli_connect_error());
} else {
$stmt = $mysqli->prepare("SELECT password FROM $authme_table WHERE username = ?");
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->bind_result($password);
if ($stmt->fetch()) {
return $password;
}
}
return null;
}
/**
* Checks the given clear-text password against the hash.
*
* @param string $password the clear-text password to check
* @param string $hash the hash to check the password against
* @return bool true iff the password matches the hash, false otherwise
*/
function authme_check_hash($password, $hash) {
// $SHA$salt$hash, where hash := sha256(sha256(password) . salt)
$parts = explode('$', $hash);
return count($parts) === 4
&& $parts[3] === hash('sha256', hash('sha256', $password) . $parts[2]);
}

View File

@ -9,8 +9,8 @@ import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import javax.inject.Inject;
import java.util.List; import java.util.concurrent.CopyOnWriteArrayList;
import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE; import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
@ -24,11 +24,13 @@ public class AntiBot {
private final Messages messages; private final Messages messages;
private final PermissionsManager permissionsManager; private final PermissionsManager permissionsManager;
private final BukkitService bukkitService; private final BukkitService bukkitService;
private final List<String> antibotPlayers = new ArrayList<>(); public final CopyOnWriteArrayList<String> antibotKicked = new CopyOnWriteArrayList<String>();
private final CopyOnWriteArrayList<String> antibotPlayers = new CopyOnWriteArrayList<String>();
private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED; private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED;
public AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager, @Inject
BukkitService bukkitService) { AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager,
BukkitService bukkitService) {
this.settings = settings; this.settings = settings;
this.messages = messages; this.messages = messages;
this.permissionsManager = permissionsManager; this.permissionsManager = permissionsManager;
@ -75,6 +77,7 @@ public class AntiBot {
if (antiBotStatus == AntiBotStatus.ACTIVE) { if (antiBotStatus == AntiBotStatus.ACTIVE) {
antiBotStatus = AntiBotStatus.LISTENING; antiBotStatus = AntiBotStatus.LISTENING;
antibotPlayers.clear(); antibotPlayers.clear();
antibotKicked.clear();
for (String s : messages.retrieve(MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE)) { for (String s : messages.retrieve(MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE)) {
bukkitService.broadcastMessage(s.replace("%m", Integer.toString(duration))); bukkitService.broadcastMessage(s.replace("%m", Integer.toString(duration)));
} }
@ -83,7 +86,12 @@ public class AntiBot {
}, duration * TICKS_PER_MINUTE); }, duration * TICKS_PER_MINUTE);
} }
public void checkAntiBot(final Player player) { /**
* Handles a player joining the server and checks if AntiBot needs to be activated.
*
* @param player the player who joined the server
*/
public void handlePlayerJoin(final Player player) {
if (antiBotStatus == AntiBotStatus.ACTIVE || antiBotStatus == AntiBotStatus.DISABLED) { if (antiBotStatus == AntiBotStatus.ACTIVE || antiBotStatus == AntiBotStatus.DISABLED) {
return; return;
} }

View File

@ -1,32 +1,5 @@
package fr.xephi.authme; package fr.xephi.authme;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import fr.xephi.authme.api.API; import fr.xephi.authme.api.API;
import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.api.NewAPI;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
@ -34,12 +7,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.backup.JsonCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.command.CommandHandler;
import fr.xephi.authme.command.CommandInitializer;
import fr.xephi.authme.command.CommandMapper;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSourceType; import fr.xephi.authme.datasource.DataSourceType;
@ -48,13 +16,15 @@ import fr.xephi.authme.datasource.MySQL;
import fr.xephi.authme.datasource.SQLite; import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.hooks.BungeeCordMessage; import fr.xephi.authme.hooks.BungeeCordMessage;
import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.MetricsStarter;
import fr.xephi.authme.listener.AuthMeBlockListener; import fr.xephi.authme.listener.AuthMeBlockListener;
import fr.xephi.authme.listener.AuthMeEntityListener; import fr.xephi.authme.listener.AuthMeEntityListener;
import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter; import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter;
import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener;
import fr.xephi.authme.listener.AuthMePlayerListener16; import fr.xephi.authme.listener.AuthMePlayerListener16;
import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMePlayerListener18;
import fr.xephi.authme.listener.AuthMePlayerListener19;
import fr.xephi.authme.listener.AuthMeServerListener; import fr.xephi.authme.listener.AuthMeServerListener;
import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter;
import fr.xephi.authme.listener.AuthMeTablistPacketAdapter; import fr.xephi.authme.listener.AuthMeTablistPacketAdapter;
@ -64,9 +34,7 @@ import fr.xephi.authme.output.Log4JFilter;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.security.crypts.SHA256;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
@ -82,6 +50,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.task.PurgeTask;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.FileUtils;
@ -89,7 +58,32 @@ import fr.xephi.authme.util.GeoLiteAPI;
import fr.xephi.authme.util.MigrationService; import fr.xephi.authme.util.MigrationService;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.ValidationService; import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
/** /**
* The AuthMe main class. * The AuthMe main class.
@ -105,17 +99,13 @@ public class AuthMe extends JavaPlugin {
// Private Instances // Private Instances
private static AuthMe plugin; private static AuthMe plugin;
private static Server server;
/* /*
* Maps and stuff * Maps and stuff
*/ */
// TODO #601: Integrate CaptchaManager
public final ConcurrentHashMap<String, BukkitTask> sessions = new ConcurrentHashMap<>(); public final ConcurrentHashMap<String, BukkitTask> sessions = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, Integer> captcha = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, String> cap = new ConcurrentHashMap<>();
/* /*
* Public Instances * Public instances
*/ */
public NewAPI api; public NewAPI api;
// TODO #655: Encapsulate mail // TODO #655: Encapsulate mail
@ -124,7 +114,6 @@ public class AuthMe extends JavaPlugin {
public DataManager dataManager; public DataManager dataManager;
/* /*
* Private instances * Private instances
* TODO #432: Move instantiation and management of these services
*/ */
// TODO #604: Encapsulate ProtocolLib members // TODO #604: Encapsulate ProtocolLib members
public AuthMeInventoryPacketAdapter inventoryProtector; public AuthMeInventoryPacketAdapter inventoryProtector;
@ -140,15 +129,16 @@ public class AuthMe extends JavaPlugin {
private DataSource database; private DataSource database;
private PluginHooks pluginHooks; private PluginHooks pluginHooks;
private SpawnLoader spawnLoader; private SpawnLoader spawnLoader;
private AntiBot antiBot;
private boolean autoPurging; private boolean autoPurging;
private BukkitService bukkitService; private BukkitService bukkitService;
private AuthMeServiceInitializer initializer;
/** /**
* Get the plugin's instance. * Get the plugin's instance.
* *
* @return AuthMe * @return AuthMe
*/ */
@Deprecated
public static AuthMe getInstance() { public static AuthMe getInstance() {
return plugin; return plugin;
} }
@ -180,24 +170,6 @@ public class AuthMe extends JavaPlugin {
return pluginBuildNumber; return pluginBuildNumber;
} }
/**
* Get the Messages instance.
*
* @return Plugin's messages.
*/
public Messages getMessages() {
return messages;
}
/**
* Get the plugin's NewSetting instance.
*
* @return NewSetting.
*/
public NewSetting getSettings() {
return newSettings;
}
// Get version and build number of the plugin // Get version and build number of the plugin
private void setPluginInfos() { private void setPluginInfos() {
String versionRaw = this.getDescription().getVersion(); String versionRaw = this.getDescription().getVersion();
@ -217,25 +189,23 @@ public class AuthMe extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// Set various instances // Set various instances
server = getServer();
plugin = this; plugin = this;
ConsoleLogger.setLogger(getLogger()); ConsoleLogger.setLogger(getLogger());
setPluginInfos(); setPluginInfos();
// Load settings and custom configurations, if it fails, stop the server due to security reasons. // Load settings and custom configurations, if it fails, stop the server due to security reasons.
newSettings = createNewSetting(); newSettings = createNewSetting();
if (newSettings == null) { if (newSettings == null) {
ConsoleLogger.showError("Could not load configuration. Aborting."); getLogger().warning("Could not load configuration. Aborting.");
server.shutdown(); getServer().shutdown();
return; return;
} }
ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING), ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log"));
new File(getDataFolder(), "authme.log")); ConsoleLogger.setLoggingOptions(newSettings);
// Old settings manager // Old settings manager
if (!loadSettings()) { if (!loadSettings()) {
server.shutdown(); getServer().shutdown();
setEnabled(false); setEnabled(false);
return; return;
} }
@ -251,23 +221,43 @@ public class AuthMe extends JavaPlugin {
stopOrUnload(); stopOrUnload();
return; return;
} }
bukkitService = new BukkitService(this);
pluginHooks = new PluginHooks(server.getPluginManager());
MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); MigrationService.changePlainTextToSha256(newSettings, database, new SHA256());
passwordSecurity = new PasswordSecurity(getDataSource(), newSettings, Bukkit.getPluginManager());
// Initialize spawn loader
spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); initializer = new AuthMeServiceInitializer("fr.xephi.authme");
permsMan = initializePermissionsManager(); // Register elements of the Bukkit / JavaPlugin environment
antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); initializer.register(AuthMe.class, this);
ValidationService validationService = new ValidationService(newSettings, database, permsMan); initializer.register(Server.class, getServer());
commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, initializer.register(PluginManager.class, getServer().getPluginManager());
pluginHooks, spawnLoader, antiBot, validationService, bukkitService); initializer.register(BukkitScheduler.class, getServer().getScheduler());
initializer.provide(DataFolder.class, getDataFolder());
// Register elements we instantiate manually
initializer.register(NewSetting.class, newSettings);
initializer.register(Messages.class, messages);
initializer.register(DataSource.class, database);
// Some statically injected things
initializer.register(PlayerCache.class, PlayerCache.getInstance());
// Note ljacqu 20160612: Instantiate LimboCache first to make sure it is instantiated
// (because sometimes it's used via LimboCache.getInstance())
// Once LimboCache#getInstance() no longer exists this can be removed!
initializer.get(LimboCache.class);
permsMan = initializer.get(PermissionsManager.class);
bukkitService = initializer.get(BukkitService.class);
pluginHooks = initializer.get(PluginHooks.class);
passwordSecurity = initializer.get(PasswordSecurity.class);
spawnLoader = initializer.get(SpawnLoader.class);
commandHandler = initializer.get(CommandHandler.class);
api = initializer.get(NewAPI.class);
management = initializer.get(Management.class);
dataManager = initializer.get(DataManager.class);
initializer.get(API.class);
// Set up Metrics // Set up Metrics
MetricsStarter.setupMetrics(plugin, newSettings); MetricsStarter.setupMetrics(this, newSettings);
// Set console filter // Set console filter
setupConsoleFilter(); setupConsoleFilter();
@ -284,32 +274,21 @@ public class AuthMe extends JavaPlugin {
// End of Hooks // End of Hooks
// Do a backup on start // Do a backup on start
new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.START); new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START);
// Setup the inventory backup // Setup the inventory backup
playerBackup = new JsonCache(); playerBackup = new JsonCache();
// Set the DataManager
dataManager = new DataManager(this, pluginHooks, bukkitService);
// Set up the new API
setupApi();
// Set up the management
ProcessService processService = new ProcessService(newSettings, messages, this, database,
passwordSecurity, pluginHooks, spawnLoader, validationService, bukkitService);
management = new Management(this, processService, database, PlayerCache.getInstance());
// Set up the BungeeCord hook // Set up the BungeeCord hook
setupBungeeCordHook(newSettings); setupBungeeCordHook(newSettings, initializer);
// Reload support hook // Reload support hook
reloadSupportHook(); reloadSupportHook();
// Register event listeners // Register event listeners
registerEventListeners( registerEventListeners(initializer);
messages, database, management, pluginHooks, spawnLoader, antiBot, bukkitService, validationService);
// Start Email recall task if needed // Start Email recall task if needed
scheduleRecallEmailTask(); scheduleRecallEmailTask();
@ -327,23 +306,6 @@ public class AuthMe extends JavaPlugin {
runAutoPurge(); runAutoPurge();
} }
/**
* Reload certain components.
*
* @throws Exception if an error occurs
*/
public void reload() throws Exception {
newSettings.reload();
// We do not change database type for consistency issues, but we'll output a note in the logs
if (!newSettings.getProperty(DatabaseSettings.BACKEND).equals(database.getType())) {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
}
database.reload();
messages.reload(newSettings.getMessagesFile());
passwordSecurity.reload();
spawnLoader.initialize(newSettings);
}
/** /**
* Set up the mail API, if enabled. * Set up the mail API, if enabled.
*/ */
@ -373,38 +335,27 @@ public class AuthMe extends JavaPlugin {
/** /**
* Register all event listeners. * Register all event listeners.
*/ */
private void registerEventListeners(Messages messages, DataSource dataSource, Management management, private void registerEventListeners(AuthMeServiceInitializer initializer) {
PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot,
BukkitService bukkitService, ValidationService validationService) {
// Get the plugin manager instance // Get the plugin manager instance
PluginManager pluginManager = server.getPluginManager(); PluginManager pluginManager = getServer().getPluginManager();
// Register event listeners // Register event listeners
pluginManager.registerEvents(new AuthMePlayerListener( pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this);
this, newSettings, messages, dataSource, antiBot, management, bukkitService, validationService), this); pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this);
pluginManager.registerEvents(new AuthMeBlockListener(), this); pluginManager.registerEvents(initializer.get(AuthMeEntityListener.class), this);
pluginManager.registerEvents(new AuthMeEntityListener(), this); pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this);
pluginManager.registerEvents(new AuthMeServerListener(
this, messages, newSettings, pluginHooks, spawnLoader, validationService), this);
// Try to register 1.6 player listeners // Try to register 1.6 player listeners
try { try {
Class.forName("org.bukkit.event.player.PlayerEditBookEvent"); Class.forName("org.bukkit.event.player.PlayerEditBookEvent");
pluginManager.registerEvents(new AuthMePlayerListener16(), this); pluginManager.registerEvents(initializer.get(AuthMePlayerListener16.class), this);
} catch (ClassNotFoundException ignore) { } catch (ClassNotFoundException ignore) {
} }
// Try to register 1.8 player listeners // Try to register 1.8 player listeners
try { try {
Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent"); Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent");
pluginManager.registerEvents(new AuthMePlayerListener18(), this); pluginManager.registerEvents(initializer.get(AuthMePlayerListener18.class), this);
} catch (ClassNotFoundException ignore) {
}
// Try to register 1.9 player listeners
try {
Class.forName("org.spigotmc.event.player.PlayerSpawnLocationEvent");
pluginManager.registerEvents(new AuthMePlayerListener19(this), this);
} catch (ClassNotFoundException ignore) { } catch (ClassNotFoundException ignore) {
} }
} }
@ -430,38 +381,14 @@ public class AuthMe extends JavaPlugin {
/** /**
* Set up the BungeeCord hook. * Set up the BungeeCord hook.
*/ */
private void setupBungeeCordHook(NewSetting settings) { private void setupBungeeCordHook(NewSetting settings, AuthMeServiceInitializer initializer) {
if (settings.getProperty(HooksSettings.BUNGEECORD)) { if (settings.getProperty(HooksSettings.BUNGEECORD)) {
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
Bukkit.getMessenger().registerIncomingPluginChannel( Bukkit.getMessenger().registerIncomingPluginChannel(
this, "BungeeCord", new BungeeCordMessage(this)); this, "BungeeCord", initializer.get(BungeeCordMessage.class));
} }
} }
private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages,
PasswordSecurity passwordSecurity, NewSetting settings,
PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot,
ValidationService validationService, BukkitService bukkitService) {
HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER));
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager);
CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity,
permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService);
return new CommandHandler(commandService);
}
/**
* Set up the API. This sets up the new and the old API.
*/
@SuppressWarnings("deprecation")
private void setupApi() {
// Set up the API
api = new NewAPI(this);
// Set up the deprecated API
new API(this);
}
/** /**
* Load the plugin's settings. * Load the plugin's settings.
* *
@ -474,7 +401,7 @@ public class AuthMe extends JavaPlugin {
} catch (Exception e) { } catch (Exception e) {
ConsoleLogger.logException("Can't load the configuration file... Something went wrong. " ConsoleLogger.logException("Can't load the configuration file... Something went wrong. "
+ "To avoid security issues the server will shut down!", e); + "To avoid security issues the server will shut down!", e);
server.shutdown(); getServer().shutdown();
} }
return false; return false;
} }
@ -492,7 +419,7 @@ public class AuthMe extends JavaPlugin {
* Set up the console filter. * Set up the console filter.
*/ */
private void setupConsoleFilter() { private void setupConsoleFilter() {
if (Settings.removePassword) { if (newSettings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
ConsoleFilter filter = new ConsoleFilter(); ConsoleFilter filter = new ConsoleFilter();
getLogger().setFilter(filter); getLogger().setFilter(filter);
Bukkit.getLogger().setFilter(filter); Bukkit.getLogger().setFilter(filter);
@ -510,33 +437,37 @@ public class AuthMe extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
// Save player data // Save player data
if (bukkitService != null) { BukkitService bukkitService = initializer.getIfAvailable(BukkitService.class);
LimboCache limboCache = initializer.getIfAvailable(LimboCache.class);
if (bukkitService != null && limboCache != null) {
Collection<? extends Player> players = bukkitService.getOnlinePlayers(); Collection<? extends Player> players = bukkitService.getOnlinePlayers();
for (Player player : players) { for (Player player : players) {
savePlayer(player); savePlayer(player, limboCache);
} }
} }
// Do backup on stop if enabled // Do backup on stop if enabled
if (newSettings != null) { if (newSettings != null) {
new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.STOP);
} }
final AuthMe pluginInstance = this;
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
List<Integer> pendingTasks = new ArrayList<>(); List<Integer> pendingTasks = new ArrayList<>();
for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) { for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) {
if (pendingTask.getOwner().equals(plugin) && !pendingTask.isSync()) { if (pendingTask.getOwner().equals(pluginInstance) && !pendingTask.isSync()) {
pendingTasks.add(pendingTask.getTaskId()); pendingTasks.add(pendingTask.getTaskId());
} }
} }
ConsoleLogger.info("Waiting for " + pendingTasks.size() + " tasks to finish"); getLogger().info("Waiting for " + pendingTasks.size() + " tasks to finish");
int progress = 0; int progress = 0;
for (int taskId : pendingTasks) { for (int taskId : pendingTasks) {
int maxTries = 5; int maxTries = 5;
while (getServer().getScheduler().isCurrentlyRunning(taskId)) { while (getServer().getScheduler().isCurrentlyRunning(taskId)) {
if (maxTries <= 0) { if (maxTries <= 0) {
ConsoleLogger.info("Async task " + taskId + " times out after to many tries"); getLogger().info("Async task " + taskId + " times out after to many tries");
break; break;
} }
try { try {
@ -547,7 +478,7 @@ public class AuthMe extends JavaPlugin {
} }
progress++; progress++;
ConsoleLogger.info("Progress: " + progress + " / " + pendingTasks.size()); getLogger().info("Progress: " + progress + " / " + pendingTasks.size());
} }
if (database != null) { if (database != null) {
database.close(); database.close();
@ -555,19 +486,18 @@ public class AuthMe extends JavaPlugin {
} }
}, "AuthMe-DataSource#close").start(); }, "AuthMe-DataSource#close").start();
// Close the database
// Disabled correctly // Disabled correctly
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
ConsoleLogger.close();
} }
// Stop/unload the server/plugin as defined in the configuration // Stop/unload the server/plugin as defined in the configuration
public void stopOrUnload() { public void stopOrUnload() {
if (Settings.isStopEnabled) { if (Settings.isStopEnabled) {
ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!"); ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!");
server.shutdown(); getServer().shutdown();
} else { } else {
server.getPluginManager().disablePlugin(AuthMe.getInstance()); getServer().getPluginManager().disablePlugin(AuthMe.getInstance());
} }
} }
@ -610,7 +540,7 @@ public class AuthMe extends JavaPlugin {
database = dataSource; database = dataSource;
if (DataSourceType.SQLITE == dataSourceType) { if (DataSourceType.SQLITE == dataSourceType) {
server.getScheduler().runTaskAsynchronously(this, new Runnable() { getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
@Override @Override
public void run() { public void run() {
int accounts = database.getAccountsRegistered(); int accounts = database.getAccountsRegistered();
@ -623,15 +553,6 @@ public class AuthMe extends JavaPlugin {
} }
} }
/**
* Set up the permissions manager.
*/
private PermissionsManager initializePermissionsManager() {
PermissionsManager manager = new PermissionsManager(Bukkit.getServer(), getLogger());
manager.setup();
return manager;
}
// Set the console filter to remove the passwords // Set the console filter to remove the passwords
private void setLog4JFilter() { private void setLog4JFilter() {
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@ -648,7 +569,7 @@ public class AuthMe extends JavaPlugin {
// Check the presence of the ProtocolLib plugin // Check the presence of the ProtocolLib plugin
public void checkProtocolLib() { public void checkProtocolLib() {
if (!server.getPluginManager().isPluginEnabled("ProtocolLib")) { if (!getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) {
ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
Settings.protectInventoryBeforeLogInEnabled = false; Settings.protectInventoryBeforeLogInEnabled = false;
@ -682,8 +603,8 @@ public class AuthMe extends JavaPlugin {
} }
// Save Player Data // Save Player Data
private void savePlayer(Player player) { private void savePlayer(Player player, LimboCache limboCache) {
if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { if (safeIsNpc(player) || Utils.isUnrestricted(player)) {
return; return;
} }
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
@ -694,8 +615,8 @@ public class AuthMe extends JavaPlugin {
.location(player.getLocation()).build(); .location(player.getLocation()).build();
database.updateQuitLoc(auth); database.updateQuitLoc(auth);
} }
if (LimboCache.getInstance().hasLimboPlayer(name)) { if (limboCache.hasLimboPlayer(name)) {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); LimboPlayer limbo = limboCache.getLimboPlayer(name);
if (!Settings.noTeleport) { if (!Settings.noTeleport) {
player.teleport(limbo.getLoc()); player.teleport(limbo.getLoc());
} }
@ -703,7 +624,7 @@ public class AuthMe extends JavaPlugin {
Utils.addNormal(player, limbo.getGroup()); Utils.addNormal(player, limbo.getGroup());
player.setOp(limbo.isOperator()); player.setOp(limbo.isOperator());
limbo.getTimeoutTask().cancel(); limbo.getTimeoutTask().cancel();
LimboCache.getInstance().deleteLimboPlayer(name); limboCache.deleteLimboPlayer(name);
if (this.playerBackup.doesCacheExist(player)) { if (this.playerBackup.doesCacheExist(player)) {
this.playerBackup.removeCache(player); this.playerBackup.removeCache(player);
} }
@ -711,14 +632,8 @@ public class AuthMe extends JavaPlugin {
PlayerCache.getInstance().removePlayer(name); PlayerCache.getInstance().removePlayer(name);
} }
// Select the player to kick when a vip player joins the server when full private boolean safeIsNpc(Player player) {
public Player generateKickPlayer(Collection<? extends Player> collection) { return pluginHooks != null && pluginHooks.isNpc(player) || player.hasMetadata("NPC");
for (Player player : collection) {
if (!getPermissionsManager().hasPermission(player, PlayerStatePermission.IS_VIP)) {
return player;
}
}
return null;
} }
// Purge inactive players from the database, as defined in the configuration // Purge inactive players from the database, as defined in the configuration
@ -726,33 +641,22 @@ public class AuthMe extends JavaPlugin {
if (!newSettings.getProperty(PurgeSettings.USE_AUTO_PURGE) || autoPurging) { if (!newSettings.getProperty(PurgeSettings.USE_AUTO_PURGE) || autoPurging) {
return; return;
} }
autoPurging = true; autoPurging = true;
server.getScheduler().runTaskAsynchronously(this, new Runnable() {
@Override ConsoleLogger.info("AutoPurging the Database...");
public void run() { Calendar calendar = Calendar.getInstance();
ConsoleLogger.info("AutoPurging the Database..."); calendar.add(Calendar.DATE, -newSettings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER));
Calendar calendar = Calendar.getInstance(); long until = calendar.getTimeInMillis();
calendar.add(Calendar.DATE, -newSettings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER)); Set<String> cleared = database.autoPurgeDatabase(until);
long until = calendar.getTimeInMillis(); if (CollectionUtils.isEmpty(cleared)) {
List<String> cleared = database.autoPurgeDatabase(until); return;
if (CollectionUtils.isEmpty(cleared)) { }
return;
} ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!");
ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!"); ConsoleLogger.info("Purging user accounts...");
if (newSettings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) && pluginHooks.isEssentialsAvailable()) new PurgeTask(plugin, Bukkit.getConsoleSender(), cleared, true, Bukkit.getOfflinePlayers())
dataManager.purgeEssentials(cleared); .runTaskTimer(plugin, 0, 1);
if (newSettings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT))
dataManager.purgeDat(cleared);
if (newSettings.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES))
dataManager.purgeLimitedCreative(cleared);
if (newSettings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE))
dataManager.purgeAntiXray(cleared);
if (newSettings.getProperty(PurgeSettings.REMOVE_PERMISSIONS))
dataManager.purgePermissions(cleared);
ConsoleLogger.info("AutoPurge Finished!");
autoPurging = false;
}
});
} }
// Return the spawn location of a player // Return the spawn location of a player
@ -784,6 +688,7 @@ public class AuthMe extends JavaPlugin {
public String replaceAllInfo(String message, Player player) { public String replaceAllInfo(String message, Player player) {
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size()); String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
String ipAddress = Utils.getPlayerIp(player); String ipAddress = Utils.getPlayerIp(player);
Server server = getServer();
return message return message
.replace("&", "\u00a7") .replace("&", "\u00a7")
.replace("{PLAYER}", player.getName()) .replace("{PLAYER}", player.getName())
@ -797,17 +702,7 @@ public class AuthMe extends JavaPlugin {
.replace("{COUNTRY}", GeoLiteAPI.getCountryName(ipAddress)); .replace("{COUNTRY}", GeoLiteAPI.getCountryName(ipAddress));
} }
public boolean isLoggedIp(String name, String ip) {
int count = 0;
for (Player player : bukkitService.getOnlinePlayers()) {
if (ip.equalsIgnoreCase(Utils.getPlayerIp(player))
&& database.isLogged(player.getName().toLowerCase())
&& !player.getName().equalsIgnoreCase(name)) {
++count;
}
}
return count >= Settings.getMaxLoginPerIp;
}
/** /**
* Handle Bukkit commands. * Handle Bukkit commands.
@ -832,34 +727,66 @@ public class AuthMe extends JavaPlugin {
return commandHandler.processCommand(sender, commandLabel, args); return commandHandler.processCommand(sender, commandLabel, args);
} }
public void notifyAutoPurgeEnd() {
this.autoPurging = false;
}
// -------------
// Service getters (deprecated)
// Use @Inject fields instead
// -------------
/** /**
* Get the permissions manager instance. * @return NewSetting
* * @deprecated should be used in API classes only (temporarily)
* @return Permissions Manager instance.
*/ */
@Deprecated
public NewSetting getSettings() {
return newSettings;
}
/**
* @return permission manager
* @deprecated should be used in API classes only (temporarily)
*/
@Deprecated
public PermissionsManager getPermissionsManager() { public PermissionsManager getPermissionsManager() {
return this.permsMan; return this.permsMan;
} }
/** /**
* Return the management instance. * @return process manager
* * @deprecated should be used in API classes only (temporarily)
* @return management The Management
*/ */
@Deprecated
public Management getManagement() { public Management getManagement() {
return management; return management;
} }
/**
* @return the datasource
* @deprecated should be used in API classes only (temporarily)
*/
@Deprecated
public DataSource getDataSource() { public DataSource getDataSource() {
return database; return database;
} }
/**
* @return password manager
* @deprecated should be used in API classes only (temporarily)
*/
@Deprecated
public PasswordSecurity getPasswordSecurity() { public PasswordSecurity getPasswordSecurity() {
return passwordSecurity; return passwordSecurity;
} }
/**
* @return plugin hooks
* @deprecated should be used in API classes only (temporarily)
*/
@Deprecated
public PluginHooks getPluginHooks() { public PluginHooks getPluginHooks() {
return pluginHooks; return pluginHooks;
} }
} }

View File

@ -1,15 +1,17 @@
package fr.xephi.authme; package fr.xephi.authme;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import java.io.File; import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
@ -20,22 +22,38 @@ public final class ConsoleLogger {
private static final String NEW_LINE = System.getProperty("line.separator"); private static final String NEW_LINE = System.getProperty("line.separator");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private static Logger logger; private static Logger logger;
private static boolean enableDebug = false;
private static boolean useLogging = false; private static boolean useLogging = false;
private static File logFile; private static File logFile;
private static FileWriter fileWriter;
private ConsoleLogger() { private ConsoleLogger() {
// Service class
} }
public static void setLogger(Logger logger) { public static void setLogger(Logger logger) {
ConsoleLogger.logger = logger; ConsoleLogger.logger = logger;
} }
public static void setLoggingOptions(boolean useLogging, File logFile) { public static void setLogFile(File logFile) {
ConsoleLogger.useLogging = useLogging;
ConsoleLogger.logFile = logFile; ConsoleLogger.logFile = logFile;
} }
public static void setLoggingOptions(NewSetting settings) {
ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING);
ConsoleLogger.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE);
if (useLogging) {
if (fileWriter == null) {
try {
fileWriter = new FileWriter(logFile, true);
} catch (IOException e) {
ConsoleLogger.logException("Failed to create the log file:", e);
}
}
} else {
close();
}
}
/** /**
* Print an info message. * Print an info message.
* *
@ -46,6 +64,20 @@ public final class ConsoleLogger {
if (useLogging) { if (useLogging) {
writeLog(message); writeLog(message);
} }
}
public static void debug(String message) {
if (enableDebug) {
//creating and filling an exception is a expensive call
//TODO #419 20160601: ->so it should be removed as soon #419 is fixed
//logger.isLoggable does not work because the plugin logger is always ALL
logger.log(Level.FINE, message + ' ' + Thread.currentThread().getName(), new Exception());
if (useLogging) {
writeLog("Debug: " + Thread.currentThread().getName() + ':' + message);
}
}
} }
/** /**
@ -71,9 +103,11 @@ public final class ConsoleLogger {
dateTime = DATE_FORMAT.format(new Date()); dateTime = DATE_FORMAT.format(new Date());
} }
try { try {
Files.write(logFile.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(), fileWriter.write(dateTime);
StandardOpenOption.APPEND, fileWriter.write(": ");
StandardOpenOption.CREATE); fileWriter.write(message);
fileWriter.write(NEW_LINE);
fileWriter.flush();
} catch (IOException ignored) { } catch (IOException ignored) {
} }
} }
@ -93,10 +127,21 @@ public final class ConsoleLogger {
* Logs a Throwable with the provided message and saves the stack trace to the log file. * Logs a Throwable with the provided message and saves the stack trace to the log file.
* *
* @param message The message to accompany the exception * @param message The message to accompany the exception
* @param th The Throwable to log * @param th The Throwable to log
*/ */
public static void logException(String message, Throwable th) { public static void logException(String message, Throwable th) {
showError(message + " " + StringUtils.formatException(th)); showError(message + " " + StringUtils.formatException(th));
writeStackTrace(th); writeStackTrace(th);
} }
public static void close() {
if (fileWriter != null) {
try {
fileWriter.flush();
fileWriter.close();
fileWriter = null;
} catch (IOException ignored) {
}
}
}
} }

View File

@ -2,52 +2,44 @@ package fr.xephi.authme;
import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.settings.properties.PurgeSettings;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import javax.inject.Inject;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import static fr.xephi.authme.util.StringUtils.makePath;
import java.util.Set;
/** /**
*/ */
public class DataManager { public class DataManager {
private final AuthMe plugin; @Inject
private final PluginHooks pluginHooks; private Server server;
private final BukkitService bukkitService; @Inject
private PluginHooks pluginHooks;
@Inject
private BukkitService bukkitService;
@Inject
private NewSetting settings;
@Inject
private PermissionsManager permissionsManager;
/* DataManager() { }
* Constructor.
*/
public DataManager(AuthMe plugin, PluginHooks pluginHooks, BukkitService bukkitService) {
this.plugin = plugin;
this.pluginHooks = pluginHooks;
this.bukkitService = bukkitService;
}
private List<OfflinePlayer> getOfflinePlayers(List<String> names) { public void purgeAntiXray(Set<String> cleared) {
List<OfflinePlayer> result = new ArrayList<>();
for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
for (String name : names) {
if (name.equalsIgnoreCase(op.getName())) {
result.add(op);
}
}
}
return result;
}
public void purgeAntiXray(List<String> cleared) {
int i = 0; int i = 0;
File dataFolder = new File("." + File.separator + "plugins" + File.separator + "AntiXRayData" File dataFolder = new File("." + File.separator + "plugins" + File.separator + "AntiXRayData"
+ File.separator + "PlayerData"); + File.separator + "PlayerData");
if (!dataFolder.exists() || !dataFolder.isDirectory()) { if (!dataFolder.exists() || !dataFolder.isDirectory()) {
return; return;
} }
for (String file : dataFolder.list()) { for (String file : dataFolder.list()) {
if (cleared.contains(file.toLowerCase())) { if (cleared.contains(file.toLowerCase())) {
File playerFile = new File(dataFolder, file); File playerFile = new File(dataFolder, file);
@ -56,10 +48,11 @@ public class DataManager {
} }
} }
} }
ConsoleLogger.info("AutoPurge: Removed " + i + " AntiXRayData Files"); ConsoleLogger.info("AutoPurge: Removed " + i + " AntiXRayData Files");
} }
public synchronized void purgeLimitedCreative(List<String> cleared) { public synchronized void purgeLimitedCreative(Set<String> cleared) {
int i = 0; int i = 0;
File dataFolder = new File("." + File.separator + "plugins" + File.separator + "LimitedCreative" File dataFolder = new File("." + File.separator + "plugins" + File.separator + "LimitedCreative"
+ File.separator + "inventories"); + File.separator + "inventories");
@ -96,18 +89,18 @@ public class DataManager {
ConsoleLogger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files"); ConsoleLogger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files");
} }
public synchronized void purgeDat(List<String> cleared) { public synchronized void purgeDat(Set<OfflinePlayer> cleared) {
int i = 0; int i = 0;
File dataFolder = new File(plugin.getServer().getWorldContainer() File dataFolder = new File(server.getWorldContainer()
+ File.separator + plugin.getSettings().getProperty(PurgeSettings.DEFAULT_WORLD) , makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players"));
+ File.separator + "players");
List<OfflinePlayer> offlinePlayers = getOfflinePlayers(cleared); for (OfflinePlayer offlinePlayer : cleared) {
for (OfflinePlayer player : offlinePlayers) { File playerFile = new File(dataFolder, Utils.getUUIDorName(offlinePlayer) + ".dat");
File playerFile = new File(dataFolder, Utils.getUUIDorName(player) + ".dat");
if (playerFile.delete()) { if (playerFile.delete()) {
i++; i++;
} }
} }
ConsoleLogger.info("AutoPurge: Removed " + i + " .dat Files"); ConsoleLogger.info("AutoPurge: Removed " + i + " .dat Files");
} }
@ -116,7 +109,7 @@ public class DataManager {
* *
* @param cleared List of String * @param cleared List of String
*/ */
public void purgeEssentials(List<String> cleared) { public void purgeEssentials(Set<OfflinePlayer> cleared) {
int i = 0; int i = 0;
File essentialsDataFolder = pluginHooks.getEssentialsDataFolder(); File essentialsDataFolder = pluginHooks.getEssentialsDataFolder();
if (essentialsDataFolder == null) { if (essentialsDataFolder == null) {
@ -128,9 +121,9 @@ public class DataManager {
if (!userDataFolder.exists() || !userDataFolder.isDirectory()) { if (!userDataFolder.exists() || !userDataFolder.isDirectory()) {
return; return;
} }
List<OfflinePlayer> offlinePlayers = getOfflinePlayers(cleared);
for (OfflinePlayer player : offlinePlayers) { for (OfflinePlayer offlinePlayer : cleared) {
File playerFile = new File(userDataFolder, Utils.getUUIDorName(player) + ".yml"); File playerFile = new File(userDataFolder, Utils.getUUIDorName(offlinePlayer) + ".yml");
if (playerFile.exists() && playerFile.delete()) { if (playerFile.exists() && playerFile.delete()) {
i++; i++;
} }
@ -141,16 +134,12 @@ public class DataManager {
// TODO: What is this method for? Is it correct? // TODO: What is this method for? Is it correct?
// TODO: Make it work with OfflinePlayers group data. // TODO: Make it work with OfflinePlayers group data.
public synchronized void purgePermissions(List<String> cleared) { public synchronized void purgePermissions(Set<OfflinePlayer> cleared) {
// Get the permissions manager, and make sure it's valid for (OfflinePlayer offlinePlayer : cleared) {
PermissionsManager permsMan = plugin.getPermissionsManager(); String name = offlinePlayer.getName();
if (permsMan == null) { permissionsManager.removeAllGroups(bukkitService.getPlayerExact(name));
ConsoleLogger.showError("Unable to access permissions manager instance!");
return;
}
for (String name : cleared) {
permsMan.removeAllGroups(bukkitService.getPlayerExact(name));
} }
ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s).");
} }
} }

View File

@ -3,6 +3,8 @@ package fr.xephi.authme.api;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
@ -12,6 +14,8 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import javax.inject.Inject;
/** /**
* Deprecated API of AuthMe. Please use {@link NewAPI} instead. * Deprecated API of AuthMe. Please use {@link NewAPI} instead.
*/ */
@ -20,7 +24,9 @@ public class API {
public static final String newline = System.getProperty("line.separator"); public static final String newline = System.getProperty("line.separator");
public static AuthMe instance; public static AuthMe instance;
private static DataSource dataSource;
private static PasswordSecurity passwordSecurity; private static PasswordSecurity passwordSecurity;
private static Management management;
/** /**
* Constructor for the deprecated API. * Constructor for the deprecated API.
@ -28,9 +34,12 @@ public class API {
* @param instance AuthMe * @param instance AuthMe
*/ */
@Deprecated @Deprecated
public API(AuthMe instance) { @Inject
API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management) {
API.instance = instance; API.instance = instance;
passwordSecurity = instance.getPasswordSecurity(); API.dataSource = dataSource;
API.passwordSecurity = passwordSecurity;
API.management = management;
} }
/** /**
@ -109,7 +118,7 @@ public class API {
@Deprecated @Deprecated
public static boolean isRegistered(String playerName) { public static boolean isRegistered(String playerName) {
String player = playerName.toLowerCase(); String player = playerName.toLowerCase();
return instance.getDataSource().isAuthAvailable(player); return dataSource.isAuthAvailable(player);
} }
/** /**
@ -144,7 +153,7 @@ public class API {
.lastLogin(0) .lastLogin(0)
.realName(playerName) .realName(playerName)
.build(); .build();
return instance.getDataSource().saveAuth(auth); return dataSource.saveAuth(auth);
} }
/** /**
@ -154,7 +163,7 @@ public class API {
*/ */
@Deprecated @Deprecated
public static void forceLogin(Player player) { public static void forceLogin(Player player) {
instance.getManagement().performLogin(player, "dontneed", true); management.performLogin(player, "dontneed", true);
} }
@Deprecated @Deprecated
@ -170,7 +179,7 @@ public class API {
*/ */
@Deprecated @Deprecated
public boolean isNPC(Player player) { public boolean isNPC(Player player) {
return Utils.isNPC(player); return instance.getPluginHooks().isNpc(player);
} }
} }

View File

@ -1,16 +1,16 @@
package fr.xephi.authme.api; package fr.xephi.authme.api;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import javax.inject.Inject;
/** /**
* The current API of AuthMe. Recommended method of retrieving the API object: * The current API of AuthMe. Recommended method of retrieving the API object:
@ -28,19 +28,11 @@ public class NewAPI {
* *
* @param plugin The AuthMe plugin instance * @param plugin The AuthMe plugin instance
*/ */
@Inject
public NewAPI(AuthMe plugin) { public NewAPI(AuthMe plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
/**
* Constructor for NewAPI.
*
* @param server The server instance
*/
public NewAPI(Server server) {
this.plugin = (AuthMe) server.getPluginManager().getPlugin("AuthMe");
}
/** /**
* Get the API object for AuthMe. * Get the API object for AuthMe.
* *
@ -96,7 +88,7 @@ public class NewAPI {
* @return true if the player is an npc * @return true if the player is an npc
*/ */
public boolean isNPC(Player player) { public boolean isNPC(Player player) {
return Utils.isNPC(player); return plugin.getPluginHooks().isNpc(player);
} }
/** /**
@ -148,10 +140,11 @@ public class NewAPI {
} }
/** /**
* Register a player with the given password. * Register an OFFLINE/ONLINE player with the given password.
* *
* @param playerName The player to register * @param playerName The player to register
* @param password The password to register the player with * @param password The password to register the player with
*
* @return true if the player was registered successfully * @return true if the player was registered successfully
*/ */
public boolean registerPlayer(String playerName, String password) { public boolean registerPlayer(String playerName, String password) {
@ -187,13 +180,24 @@ public class NewAPI {
} }
/** /**
* Register a player with the given password. * Force an ONLINE player to register.
*
* @param player The player to register
* @param password The password to use
* @param autoLogin Should the player be authenticated automatically after the registration?
*/
public void forceRegister(Player player, String password, boolean autoLogin) {
plugin.getManagement().performRegister(player, password, null, autoLogin);
}
/**
* Register an ONLINE player with the given password.
* *
* @param player The player to register * @param player The player to register
* @param password The password to use * @param password The password to use
*/ */
public void forceRegister(Player player, String password) { public void forceRegister(Player player, String password) {
plugin.getManagement().performRegister(player, password, null); forceRegister(player, password, true);
} }
/** /**

View File

@ -1,81 +1,132 @@
package fr.xephi.authme.cache; package fr.xephi.authme.cache;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import javax.inject.Inject;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Manager for the handling of captchas. * Manager for the handling of captchas.
*/ */
public class CaptchaManager { public class CaptchaManager implements SettingsDependent {
private final int threshold;
private final int captchaLength;
private final ConcurrentHashMap<String, Integer> playerCounts; private final ConcurrentHashMap<String, Integer> playerCounts;
private final ConcurrentHashMap<String, String> captchaCodes; private final ConcurrentHashMap<String, String> captchaCodes;
public CaptchaManager(NewSetting settings) { private boolean isEnabled;
private int threshold;
private int captchaLength;
@Inject
CaptchaManager(NewSetting settings) {
this.playerCounts = new ConcurrentHashMap<>(); this.playerCounts = new ConcurrentHashMap<>();
this.captchaCodes = new ConcurrentHashMap<>(); this.captchaCodes = new ConcurrentHashMap<>();
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA); loadSettings(settings);
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
} }
public void increaseCount(String player) { /**
String playerLower = player.toLowerCase(); * Increases the failure count for the given player.
Integer currentCount = playerCounts.get(playerLower); *
if (currentCount == null) { * @param name the player's name
playerCounts.put(playerLower, 1); */
} else { public void increaseCount(String name) {
playerCounts.put(playerLower, currentCount + 1); if (isEnabled) {
String playerLower = name.toLowerCase();
Integer currentCount = playerCounts.get(playerLower);
if (currentCount == null) {
playerCounts.put(playerLower, 1);
} else {
playerCounts.put(playerLower, currentCount + 1);
}
} }
} }
/** /**
* Return whether the given player is required to solve a captcha. * Returns whether the given player is required to solve a captcha.
* *
* @param player The player to verify * @param name the name of the player to verify
* @return True if the player has to solve a captcha, false otherwise * @return true if the player has to solve a captcha, false otherwise
*/ */
public boolean isCaptchaRequired(String player) { public boolean isCaptchaRequired(String name) {
Integer count = playerCounts.get(player.toLowerCase()); if (isEnabled) {
return count != null && count >= threshold; Integer count = playerCounts.get(name.toLowerCase());
return count != null && count >= threshold;
}
return false;
} }
/** /**
* Return the captcha code for the player. Creates one if none present, so call only after * Returns the stored captcha code for the player.
* checking with {@link #isCaptchaRequired}.
* *
* @param player The player * @param name the player's name
* @return The code required for the player * @return the code the player is required to enter, or null if none registered
*/ */
public String getCaptchaCode(String player) { public String getCaptchaCode(String name) {
String code = captchaCodes.get(player.toLowerCase()); return captchaCodes.get(name.toLowerCase());
if (code == null) { }
code = RandomString.generate(captchaLength);
captchaCodes.put(player.toLowerCase(), code); /**
} * Returns the stored captcha for the player or generates and saves a new one.
*
* @param name the player's name
* @return the code the player is required to enter
*/
public String getCaptchaCodeOrGenerateNew(String name) {
String code = getCaptchaCode(name);
return code == null ? generateCode(name) : code;
}
/**
* Generates a code for the player and returns it.
*
* @param name the name of the player to generate a code for
* @return the generated code
*/
public String generateCode(String name) {
String code = RandomString.generate(captchaLength);
captchaCodes.put(name.toLowerCase(), code);
return code; return code;
} }
/** /**
* Return whether the supplied code is correct for the given player. * Checks the given code against the existing one and resets the player's auth failure count upon success.
* *
* @param player The player to check * @param name the name of the player to check
* @param code The supplied code * @param code the supplied code
* @return True if the code matches or if no captcha is required for the player, false otherwise * @return true if the code matches or if no captcha is required for the player, false otherwise
*/ */
public boolean checkCode(String player, String code) { public boolean checkCode(String name, String code) {
String savedCode = captchaCodes.get(player.toLowerCase()); String savedCode = captchaCodes.get(name.toLowerCase());
if (savedCode == null) { if (savedCode == null) {
return true; return true;
} else if (savedCode.equalsIgnoreCase(code)) { } else if (savedCode.equalsIgnoreCase(code)) {
captchaCodes.remove(player.toLowerCase()); captchaCodes.remove(name.toLowerCase());
playerCounts.remove(name.toLowerCase());
return true; return true;
} }
return false; return false;
} }
/**
* Resets the login count of the given player to 0.
*
* @param name the player's name
*/
public void resetCounts(String name) {
if (isEnabled) {
captchaCodes.remove(name.toLowerCase());
playerCounts.remove(name.toLowerCase());
}
}
@Override
public void loadSettings(NewSetting settings) {
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
}
} }

View File

@ -0,0 +1,116 @@
package fr.xephi.authme.cache;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
/**
* Manager for handling tempbans
*/
// TODO Gnat008 20160613: Figure out the best way to remove entries based on time
public class TempbanManager implements SettingsDependent {
private static final long MINUTE_IN_MILLISECONDS = 60000;
private final ConcurrentHashMap<String, Integer> ipLoginFailureCounts;
private final BukkitService bukkitService;
private final Messages messages;
private boolean isEnabled;
private int threshold;
private int length;
@Inject
TempbanManager(BukkitService bukkitService, Messages messages, NewSetting settings) {
this.ipLoginFailureCounts = new ConcurrentHashMap<>();
this.bukkitService = bukkitService;
this.messages = messages;
loadSettings(settings);
}
/**
* Increases the failure count for the given IP address.
*
* @param address The player's IP address
*/
public void increaseCount(String address) {
if (isEnabled) {
Integer count = ipLoginFailureCounts.get(address);
if (count == null) {
ipLoginFailureCounts.put(address, 1);
} else {
ipLoginFailureCounts.put(address, count + 1);
}
}
}
/**
* Set the failure count for a given IP address to 0.
*
* @param address The IP address
*/
public void resetCount(String address) {
if (isEnabled) {
ipLoginFailureCounts.remove(address);
}
}
/**
* Return whether the IP address should be tempbanned.
*
* @param address The player's IP address
* @return True if the IP should be tempbanned
*/
public boolean shouldTempban(String address) {
if (isEnabled) {
Integer count = ipLoginFailureCounts.get(address);
return count != null && count >= threshold;
}
return false;
}
/**
* Tempban a player's IP address for failing to log in too many times.
* This calculates the expire time based on the time the method was called.
*
* @param player The player to tempban
*/
public void tempbanPlayer(final Player player) {
if (isEnabled) {
final String ip = Utils.getPlayerIp(player);
final String reason = messages.retrieveSingle(MessageKey.TEMPBAN_MAX_LOGINS);
final Date expires = new Date();
long newTime = expires.getTime() + (length * MINUTE_IN_MILLISECONDS);
expires.setTime(newTime);
bukkitService.scheduleSyncDelayedTask(new Runnable() {
@Override
public void run() {
bukkitService.banIp(ip, reason, expires, "AuthMe");
player.kickPlayer(reason);
}
});
resetCount(ip);
}
}
@Override
public void loadSettings(NewSetting settings) {
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
}
}

View File

@ -1,5 +1,7 @@
package fr.xephi.authme.cache.auth; package fr.xephi.authme.cache.auth;
import fr.xephi.authme.ConsoleLogger;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
@ -22,6 +24,7 @@ public class PlayerCache {
if (singleton == null) { if (singleton == null) {
singleton = new PlayerCache(); singleton = new PlayerCache();
} }
return singleton; return singleton;
} }
@ -31,6 +34,7 @@ public class PlayerCache {
* @param auth PlayerAuth * @param auth PlayerAuth
*/ */
public void addPlayer(PlayerAuth auth) { public void addPlayer(PlayerAuth auth) {
ConsoleLogger.debug("ADDED PLAYER TO CACHE " + auth.getNickname());
cache.put(auth.getNickname().toLowerCase(), auth); cache.put(auth.getNickname().toLowerCase(), auth);
} }
@ -40,6 +44,7 @@ public class PlayerCache {
* @param auth PlayerAuth * @param auth PlayerAuth
*/ */
public void updatePlayer(PlayerAuth auth) { public void updatePlayer(PlayerAuth auth) {
ConsoleLogger.debug("UPDATE PLAYER " + auth.getNickname());
cache.put(auth.getNickname(), auth); cache.put(auth.getNickname(), auth);
} }
@ -49,6 +54,7 @@ public class PlayerCache {
* @param user String * @param user String
*/ */
public void removePlayer(String user) { public void removePlayer(String user) {
ConsoleLogger.debug("REMOVE PLAYER " + user);
cache.remove(user.toLowerCase()); cache.remove(user.toLowerCase());
} }

View File

@ -1,46 +1,34 @@
package fr.xephi.authme.cache.limbo; package fr.xephi.authme.cache.limbo;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.backup.JsonCache;
import fr.xephi.authme.cache.backup.PlayerData; import fr.xephi.authme.cache.backup.PlayerData;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.SpawnLoader;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Manages all {@link LimboPlayer} instances.
*/ */
public class LimboCache { public class LimboCache {
private volatile static LimboCache singleton; private final ConcurrentHashMap<String, LimboPlayer> cache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, LimboPlayer> cache; private final JsonCache jsonCache = new JsonCache();
private final AuthMe plugin;
private final JsonCache jsonCache;
/** @Inject
* Constructor for LimboCache. private PermissionsManager permissionsManager;
* @Inject
* @param plugin AuthMe private SpawnLoader spawnLoader;
*/
private LimboCache(AuthMe plugin) {
this.plugin = plugin;
this.cache = new ConcurrentHashMap<>();
this.jsonCache = new JsonCache();
}
/** @Inject
* Method getInstance. LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader) {
* this.permissionsManager = permissionsManager;
* @return LimboCache this.spawnLoader = spawnLoader;
*/
public static LimboCache getInstance() {
if (singleton == null) {
singleton = new LimboCache(AuthMe.getInstance());
}
return singleton;
} }
/** /**
@ -50,13 +38,12 @@ public class LimboCache {
*/ */
public void addLimboPlayer(Player player) { public void addLimboPlayer(Player player) {
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
Location loc = player.getLocation(); Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation();
boolean operator = player.isOp(); boolean operator = player.isOp();
boolean flyEnabled = player.getAllowFlight(); boolean flyEnabled = player.getAllowFlight();
String playerGroup = ""; String playerGroup = "";
PermissionsManager permsMan = plugin.getPermissionsManager(); if (permissionsManager.hasGroupSupport()) {
if (permsMan.hasGroupSupport()) { playerGroup = permissionsManager.getPrimaryGroup(player);
playerGroup = permsMan.getPrimaryGroup(player);
} }
if (jsonCache.doesCacheExist(player)) { if (jsonCache.doesCacheExist(player)) {
@ -68,11 +55,8 @@ public class LimboCache {
} }
} }
if (player.isDead()) {
loc = plugin.getSpawnLocation(player);
}
cache.put(name, new LimboPlayer(name, loc, operator, playerGroup, flyEnabled)); cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled));
} }
/** /**
@ -83,9 +67,9 @@ public class LimboCache {
public void deleteLimboPlayer(String name) { public void deleteLimboPlayer(String name) {
checkNotNull(name); checkNotNull(name);
name = name.toLowerCase(); name = name.toLowerCase();
if (cache.containsKey(name)) { LimboPlayer cachedPlayer = cache.remove(name);
cache.get(name).clearTasks(); if (cachedPlayer != null) {
cache.remove(name); cachedPlayer.clearTasks();
} }
} }

View File

@ -1,6 +1,5 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
@ -14,7 +13,7 @@ import static java.util.Arrays.asList;
/** /**
* Command description defines which labels ("names") will lead to a command and points to the * Command description defines which labels ("names") will lead to a command and points to the
* {@link ExecutableCommand} implementation that executes the logic of the command. * {@link ExecutableCommand} implementation that executes the logic of the command.
* * <p>
* CommandDescription instances are built hierarchically: they have one parent, or {@code null} for base commands * CommandDescription instances are built hierarchically: they have one parent, or {@code null} for base commands
* (main commands such as {@code /authme}), and may have multiple children extending the mapping of the parent: e.g. if * (main commands such as {@code /authme}), and may have multiple children extending the mapping of the parent: e.g. if
* {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that * {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that
@ -36,9 +35,9 @@ public class CommandDescription {
*/ */
private String detailedDescription; private String detailedDescription;
/** /**
* The executable command instance described by this object. * The class implementing the command described by this object.
*/ */
private ExecutableCommand executableCommand; private Class<? extends ExecutableCommand> executableCommand;
/** /**
* The parent command. * The parent command.
*/ */
@ -52,13 +51,13 @@ public class CommandDescription {
*/ */
private List<CommandArgumentDescription> arguments; private List<CommandArgumentDescription> arguments;
/** /**
* Command permissions required to execute this command. * Permission node required to execute this command.
*/ */
private CommandPermissions permissions; private PermissionNode permission;
/** /**
* Private constructor. Use {@link CommandDescription#builder()} to create instances of this class. * Private constructor. Use {@link CommandDescription#builder()} to create instances of this class.
* <p /> * <p>
* Note for developers: Instances should be created with {@link CommandDescription#createInstance} to be properly * Note for developers: Instances should be created with {@link CommandDescription#createInstance} to be properly
* registered in the command tree. * registered in the command tree.
*/ */
@ -68,21 +67,20 @@ public class CommandDescription {
/** /**
* Create an instance. * Create an instance.
* *
* @param labels List of command labels. * @param labels command labels
* @param description Command description. * @param description description of the command
* @param detailedDescription Detailed comment description. * @param detailedDescription detailed command description
* @param executableCommand The executable command, or null. * @param executableCommand class of the command implementation
* @param parent Parent command. * @param parent parent command
* @param arguments Command arguments. * @param arguments command arguments
* @param permissions The permissions required to execute this command. * @param permission permission node required to execute this command
* *
* @return The created instance * @return the created instance
* @see CommandDescription#builder() * @see CommandDescription#builder()
*/ */
private static CommandDescription createInstance(List<String> labels, String description, private static CommandDescription createInstance(List<String> labels, String description,
String detailedDescription, ExecutableCommand executableCommand, String detailedDescription, Class<? extends ExecutableCommand> executableCommand, CommandDescription parent,
CommandDescription parent, List<CommandArgumentDescription> arguments, List<CommandArgumentDescription> arguments, PermissionNode permission) {
CommandPermissions permissions) {
CommandDescription instance = new CommandDescription(); CommandDescription instance = new CommandDescription();
instance.labels = labels; instance.labels = labels;
instance.description = description; instance.description = description;
@ -90,7 +88,7 @@ public class CommandDescription {
instance.executableCommand = executableCommand; instance.executableCommand = executableCommand;
instance.parent = parent; instance.parent = parent;
instance.arguments = arguments; instance.arguments = arguments;
instance.permissions = permissions; instance.permission = permission;
if (parent != null) { if (parent != null) {
parent.addChild(instance); parent.addChild(instance);
@ -114,7 +112,7 @@ public class CommandDescription {
} }
/** /**
* Check whether this command description has a specific command. * Check whether this command description has the given label.
* *
* @param commandLabel The label to check for. * @param commandLabel The label to check for.
* *
@ -130,18 +128,18 @@ public class CommandDescription {
} }
/** /**
* Return the {@link ExecutableCommand} instance defined by the command description. * Return the {@link ExecutableCommand} class implementing this command.
* *
* @return The executable command object. * @return The executable command class
*/ */
public ExecutableCommand getExecutableCommand() { public Class<? extends ExecutableCommand> getExecutableCommand() {
return executableCommand; return executableCommand;
} }
/** /**
* Return the parent. * Return the parent.
* *
* @return The parent command, or null for base commands. * @return The parent command, or null for base commands
*/ */
public CommandDescription getParent() { public CommandDescription getParent() {
return parent; return parent;
@ -196,12 +194,12 @@ public class CommandDescription {
} }
/** /**
* Return the permissions required to execute the command. * Return the permission node required to execute the command.
* *
* @return The command permissions, or null if none are required to execute the command. * @return The permission node, or null if none are required to execute the command.
*/ */
public CommandPermissions getCommandPermissions() { public PermissionNode getPermission() {
return permissions; return permission;
} }
/** /**
@ -220,10 +218,10 @@ public class CommandDescription {
private List<String> labels; private List<String> labels;
private String description; private String description;
private String detailedDescription; private String detailedDescription;
private ExecutableCommand executableCommand; private Class<? extends ExecutableCommand> executableCommand;
private CommandDescription parent; private CommandDescription parent;
private List<CommandArgumentDescription> arguments = new ArrayList<>(); private List<CommandArgumentDescription> arguments = new ArrayList<>();
private CommandPermissions permissions; private PermissionNode permission;
/** /**
* Build a CommandDescription from the builder or throw an exception if a mandatory * Build a CommandDescription from the builder or throw an exception if a mandatory
@ -239,7 +237,7 @@ public class CommandDescription {
// parents and permissions may be null; arguments may be empty // parents and permissions may be null; arguments may be empty
return createInstance(labels, description, detailedDescription, executableCommand, return createInstance(labels, description, detailedDescription, executableCommand,
parent, arguments, permissions); parent, arguments, permission);
} }
public CommandBuilder labels(List<String> labels) { public CommandBuilder labels(List<String> labels) {
@ -261,7 +259,7 @@ public class CommandDescription {
return this; return this;
} }
public CommandBuilder executableCommand(ExecutableCommand executableCommand) { public CommandBuilder executableCommand(Class<? extends ExecutableCommand> executableCommand) {
this.executableCommand = executableCommand; this.executableCommand = executableCommand;
return this; return this;
} }
@ -286,9 +284,14 @@ public class CommandDescription {
return this; return this;
} }
public CommandBuilder permissions(DefaultPermission defaultPermission, /**
PermissionNode... permissionNodes) { * Add a permission node that a user must have to execute the command.
this.permissions = new CommandPermissions(asList(permissionNodes), defaultPermission); *
* @param permission The PermissionNode to add
* @return The builder
*/
public CommandBuilder permission(PermissionNode permission) {
this.permission = permission;
return this; return this;
} }
} }

View File

@ -1,18 +1,23 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import java.util.ArrayList;
import java.util.List;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import fr.xephi.authme.util.StringUtils; import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription} * The AuthMe command handler, responsible for invoking the correct {@link ExecutableCommand} based on incoming
* or to display help messages for unknown invocations. * command labels or for displaying a help message for unknown command labels.
*/ */
public class CommandHandler { public class CommandHandler {
@ -22,15 +27,22 @@ public class CommandHandler {
*/ */
private static final double SUGGEST_COMMAND_THRESHOLD = 0.75; private static final double SUGGEST_COMMAND_THRESHOLD = 0.75;
private final CommandService commandService; private final CommandMapper commandMapper;
private final PermissionsManager permissionsManager;
private final HelpProvider helpProvider;
/** /**
* Create a command handler. * Map with ExecutableCommand children. The key is the type of the value.
*
* @param commandService The CommandService instance
*/ */
public CommandHandler(CommandService commandService) { private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
this.commandService = commandService;
@Inject
public CommandHandler(AuthMeServiceInitializer initializer, CommandMapper commandMapper,
PermissionsManager permissionsManager, HelpProvider helpProvider) {
this.commandMapper = commandMapper;
this.permissionsManager = permissionsManager;
this.helpProvider = helpProvider;
initializeCommands(initializer, commandMapper.getCommandClasses());
} }
/** /**
@ -48,7 +60,7 @@ public class CommandHandler {
List<String> parts = skipEmptyArguments(bukkitArgs); List<String> parts = skipEmptyArguments(bukkitArgs);
parts.add(0, bukkitCommandLabel); parts.add(0, bukkitCommandLabel);
FoundCommandResult result = commandService.mapPartsToCommand(sender, parts); FoundCommandResult result = commandMapper.mapPartsToCommand(sender, parts);
handleCommandResult(sender, result); handleCommandResult(sender, result);
return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus()); return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus());
} }
@ -75,6 +87,18 @@ public class CommandHandler {
} }
} }
/**
* Initialize all required ExecutableCommand objects.
*
* @param commandClasses the classes to instantiate
*/
private void initializeCommands(AuthMeServiceInitializer initializer,
Set<Class<? extends ExecutableCommand>> commandClasses) {
for (Class<? extends ExecutableCommand> clazz : commandClasses) {
commands.put(clazz, initializer.newInstance(clazz));
}
}
/** /**
* Execute the command for the given command sender. * Execute the command for the given command sender.
* *
@ -82,9 +106,9 @@ public class CommandHandler {
* @param result The mapped result * @param result The mapped result
*/ */
private void executeCommand(CommandSender sender, FoundCommandResult result) { private void executeCommand(CommandSender sender, FoundCommandResult result) {
ExecutableCommand executableCommand = result.getCommandDescription().getExecutableCommand(); ExecutableCommand executableCommand = commands.get(result.getCommandDescription().getExecutableCommand());
List<String> arguments = result.getArguments(); List<String> arguments = result.getArguments();
executableCommand.executeCommand(sender, arguments, commandService); executableCommand.executeCommand(sender, arguments);
} }
/** /**
@ -125,14 +149,14 @@ public class CommandHandler {
private void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result) { private void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result) {
CommandDescription command = result.getCommandDescription(); CommandDescription command = result.getCommandDescription();
if (!commandService.getPermissionsManager().hasPermission(sender, command)) { if (!permissionsManager.hasPermission(sender, command.getPermission())) {
sendPermissionDeniedError(sender); sendPermissionDeniedError(sender);
return; return;
} }
// Show the command argument help // Show the command argument help
sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!"); sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!");
commandService.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS); helpProvider.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS);
List<String> labels = result.getLabels(); List<String> labels = result.getLabels();
String childLabel = labels.size() >= 2 ? labels.get(1) : ""; String childLabel = labels.size() >= 2 ? labels.get(1) : "";

View File

@ -41,25 +41,33 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static fr.xephi.authme.permission.DefaultPermission.ALLOWED;
import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
/** /**
* Initializes all available AuthMe commands. * Initializes all available AuthMe commands.
*/ */
public final class CommandInitializer { public class CommandInitializer {
private CommandInitializer() { private Set<CommandDescription> commands;
// Helper class
public CommandInitializer() {
buildCommands();
} }
public static Set<CommandDescription> buildCommands() { /**
* Returns the description of all AuthMe commands.
*
* @return the command descriptions
*/
public Set<CommandDescription> getCommands() {
return commands;
}
private void buildCommands() {
// Register the base AuthMe Reloaded command // Register the base AuthMe Reloaded command
final CommandDescription AUTHME_BASE = CommandDescription.builder() final CommandDescription AUTHME_BASE = CommandDescription.builder()
.labels("authme") .labels("authme")
.description("Main command") .description("Main command")
.detailedDescription("The main AuthMeReloaded command. The root for all admin commands.") .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.")
.executableCommand(new AuthMeCommand()) .executableCommand(AuthMeCommand.class)
.build(); .build();
// Register the register command // Register the register command
@ -70,8 +78,8 @@ public final class CommandInitializer {
.detailedDescription("Register the specified player with the specified password.") .detailedDescription("Register the specified player with the specified password.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.withArgument("password", "Password", false) .withArgument("password", "Password", false)
.permissions(OP_ONLY, AdminPermission.REGISTER) .permission(AdminPermission.REGISTER)
.executableCommand(new RegisterAdminCommand()) .executableCommand(RegisterAdminCommand.class)
.build(); .build();
// Register the unregister command // Register the unregister command
@ -81,8 +89,8 @@ public final class CommandInitializer {
.description("Unregister a player") .description("Unregister a player")
.detailedDescription("Unregister the specified player.") .detailedDescription("Unregister the specified player.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.permissions(OP_ONLY, AdminPermission.UNREGISTER) .permission(AdminPermission.UNREGISTER)
.executableCommand(new UnregisterAdminCommand()) .executableCommand(UnregisterAdminCommand.class)
.build(); .build();
// Register the forcelogin command // Register the forcelogin command
@ -92,8 +100,8 @@ public final class CommandInitializer {
.description("Enforce login player") .description("Enforce login player")
.detailedDescription("Enforce the specified player to login.") .detailedDescription("Enforce the specified player to login.")
.withArgument("player", "Online player name", true) .withArgument("player", "Online player name", true)
.permissions(OP_ONLY, AdminPermission.FORCE_LOGIN) .permission(AdminPermission.FORCE_LOGIN)
.executableCommand(new ForceLoginCommand()) .executableCommand(ForceLoginCommand.class)
.build(); .build();
// Register the changepassword command // Register the changepassword command
@ -104,8 +112,8 @@ public final class CommandInitializer {
.detailedDescription("Change the password of a player.") .detailedDescription("Change the password of a player.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.withArgument("pwd", "New password", false) .withArgument("pwd", "New password", false)
.permissions(OP_ONLY, AdminPermission.CHANGE_PASSWORD) .permission(AdminPermission.CHANGE_PASSWORD)
.executableCommand(new ChangePasswordAdminCommand()) .executableCommand(ChangePasswordAdminCommand.class)
.build(); .build();
// Register the last login command // Register the last login command
@ -115,8 +123,8 @@ public final class CommandInitializer {
.description("Player's last login") .description("Player's last login")
.detailedDescription("View the date of the specified players last login.") .detailedDescription("View the date of the specified players last login.")
.withArgument("player", "Player name", true) .withArgument("player", "Player name", true)
.permissions(OP_ONLY, AdminPermission.LAST_LOGIN) .permission(AdminPermission.LAST_LOGIN)
.executableCommand(new LastLoginCommand()) .executableCommand(LastLoginCommand.class)
.build(); .build();
// Register the accounts command // Register the accounts command
@ -126,8 +134,8 @@ public final class CommandInitializer {
.description("Display player accounts") .description("Display player accounts")
.detailedDescription("Display all accounts of a player by his player name or IP.") .detailedDescription("Display all accounts of a player by his player name or IP.")
.withArgument("player", "Player name or IP", true) .withArgument("player", "Player name or IP", true)
.permissions(OP_ONLY, AdminPermission.ACCOUNTS) .permission(AdminPermission.ACCOUNTS)
.executableCommand(new AccountsCommand()) .executableCommand(AccountsCommand.class)
.build(); .build();
// Register the getemail command // Register the getemail command
@ -137,8 +145,8 @@ public final class CommandInitializer {
.description("Display player's email") .description("Display player's email")
.detailedDescription("Display the email address of the specified player if set.") .detailedDescription("Display the email address of the specified player if set.")
.withArgument("player", "Player name", true) .withArgument("player", "Player name", true)
.permissions(OP_ONLY, AdminPermission.GET_EMAIL) .permission(AdminPermission.GET_EMAIL)
.executableCommand(new GetEmailCommand()) .executableCommand(GetEmailCommand.class)
.build(); .build();
// Register the setemail command // Register the setemail command
@ -149,8 +157,8 @@ public final class CommandInitializer {
.detailedDescription("Change the email address of the specified player.") .detailedDescription("Change the email address of the specified player.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.withArgument("email", "Player email", false) .withArgument("email", "Player email", false)
.permissions(OP_ONLY, AdminPermission.CHANGE_EMAIL) .permission(AdminPermission.CHANGE_EMAIL)
.executableCommand(new SetEmailCommand()) .executableCommand(SetEmailCommand.class)
.build(); .build();
// Register the getip command // Register the getip command
@ -160,8 +168,8 @@ public final class CommandInitializer {
.description("Get player's IP") .description("Get player's IP")
.detailedDescription("Get the IP address of the specified online player.") .detailedDescription("Get the IP address of the specified online player.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.permissions(OP_ONLY, AdminPermission.GET_IP) .permission(AdminPermission.GET_IP)
.executableCommand(new GetIpCommand()) .executableCommand(GetIpCommand.class)
.build(); .build();
// Register the spawn command // Register the spawn command
@ -170,8 +178,8 @@ public final class CommandInitializer {
.labels("spawn", "home") .labels("spawn", "home")
.description("Teleport to spawn") .description("Teleport to spawn")
.detailedDescription("Teleport to the spawn.") .detailedDescription("Teleport to the spawn.")
.permissions(OP_ONLY, AdminPermission.SPAWN) .permission(AdminPermission.SPAWN)
.executableCommand(new SpawnCommand()) .executableCommand(SpawnCommand.class)
.build(); .build();
// Register the setspawn command // Register the setspawn command
@ -180,8 +188,8 @@ public final class CommandInitializer {
.labels("setspawn", "chgspawn") .labels("setspawn", "chgspawn")
.description("Change the spawn") .description("Change the spawn")
.detailedDescription("Change the player's spawn to your current position.") .detailedDescription("Change the player's spawn to your current position.")
.permissions(OP_ONLY, AdminPermission.SET_SPAWN) .permission(AdminPermission.SET_SPAWN)
.executableCommand(new SetSpawnCommand()) .executableCommand(SetSpawnCommand.class)
.build(); .build();
// Register the firstspawn command // Register the firstspawn command
@ -190,8 +198,8 @@ public final class CommandInitializer {
.labels("firstspawn", "firsthome") .labels("firstspawn", "firsthome")
.description("Teleport to first spawn") .description("Teleport to first spawn")
.detailedDescription("Teleport to the first spawn.") .detailedDescription("Teleport to the first spawn.")
.permissions(OP_ONLY, AdminPermission.FIRST_SPAWN) .permission(AdminPermission.FIRST_SPAWN)
.executableCommand(new FirstSpawnCommand()) .executableCommand(FirstSpawnCommand.class)
.build(); .build();
// Register the setfirstspawn command // Register the setfirstspawn command
@ -200,8 +208,8 @@ public final class CommandInitializer {
.labels("setfirstspawn", "chgfirstspawn") .labels("setfirstspawn", "chgfirstspawn")
.description("Change the first spawn") .description("Change the first spawn")
.detailedDescription("Change the first player's spawn to your current position.") .detailedDescription("Change the first player's spawn to your current position.")
.permissions(OP_ONLY, AdminPermission.SET_FIRST_SPAWN) .permission(AdminPermission.SET_FIRST_SPAWN)
.executableCommand(new SetFirstSpawnCommand()) .executableCommand(SetFirstSpawnCommand.class)
.build(); .build();
// Register the purge command // Register the purge command
@ -211,8 +219,8 @@ public final class CommandInitializer {
.description("Purge old data") .description("Purge old data")
.detailedDescription("Purge old AuthMeReloaded data longer than the specified amount of days ago.") .detailedDescription("Purge old AuthMeReloaded data longer than the specified amount of days ago.")
.withArgument("days", "Number of days", false) .withArgument("days", "Number of days", false)
.permissions(OP_ONLY, AdminPermission.PURGE) .permission(AdminPermission.PURGE)
.executableCommand(new PurgeCommand()) .executableCommand(PurgeCommand.class)
.build(); .build();
// Register the purgelastposition command // Register the purgelastposition command
@ -223,8 +231,8 @@ public final class CommandInitializer {
.description("Purge player's last position") .description("Purge player's last position")
.detailedDescription("Purge the last know position of the specified player or all of them.") .detailedDescription("Purge the last know position of the specified player or all of them.")
.withArgument("player/*", "Player name or * for all players", false) .withArgument("player/*", "Player name or * for all players", false)
.permissions(OP_ONLY, AdminPermission.PURGE_LAST_POSITION) .permission(AdminPermission.PURGE_LAST_POSITION)
.executableCommand(new PurgeLastPositionCommand()) .executableCommand(PurgeLastPositionCommand.class)
.build(); .build();
// Register the purgebannedplayers command // Register the purgebannedplayers command
@ -233,8 +241,8 @@ public final class CommandInitializer {
.labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer") .labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer")
.description("Purge banned players data") .description("Purge banned players data")
.detailedDescription("Purge all AuthMeReloaded data for banned players.") .detailedDescription("Purge all AuthMeReloaded data for banned players.")
.permissions(OP_ONLY, AdminPermission.PURGE_BANNED_PLAYERS) .permission(AdminPermission.PURGE_BANNED_PLAYERS)
.executableCommand(new PurgeBannedPlayersCommand()) .executableCommand(PurgeBannedPlayersCommand.class)
.build(); .build();
// Register the switchantibot command // Register the switchantibot command
@ -244,8 +252,8 @@ public final class CommandInitializer {
.description("Switch AntiBot mode") .description("Switch AntiBot mode")
.detailedDescription("Switch or toggle the AntiBot mode to the specified state.") .detailedDescription("Switch or toggle the AntiBot mode to the specified state.")
.withArgument("mode", "ON / OFF", true) .withArgument("mode", "ON / OFF", true)
.permissions(OP_ONLY, AdminPermission.SWITCH_ANTIBOT) .permission(AdminPermission.SWITCH_ANTIBOT)
.executableCommand(new SwitchAntiBotCommand()) .executableCommand(SwitchAntiBotCommand.class)
.build(); .build();
// Register the reload command // Register the reload command
@ -254,8 +262,8 @@ public final class CommandInitializer {
.labels("reload", "rld") .labels("reload", "rld")
.description("Reload plugin") .description("Reload plugin")
.detailedDescription("Reload the AuthMeReloaded plugin.") .detailedDescription("Reload the AuthMeReloaded plugin.")
.permissions(OP_ONLY, AdminPermission.RELOAD) .permission(AdminPermission.RELOAD)
.executableCommand(new ReloadCommand()) .executableCommand(ReloadCommand.class)
.build(); .build();
// Register the version command // Register the version command
@ -265,7 +273,7 @@ public final class CommandInitializer {
.description("Version info") .description("Version info")
.detailedDescription("Show detailed information about the installed AuthMeReloaded version, the " .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the "
+ "developers, contributors, and license.") + "developers, contributors, and license.")
.executableCommand(new VersionCommand()) .executableCommand(VersionCommand.class)
.build(); .build();
CommandDescription.builder() CommandDescription.builder()
@ -275,19 +283,19 @@ public final class CommandInitializer {
.detailedDescription("Converter command for AuthMeReloaded.") .detailedDescription("Converter command for AuthMeReloaded.")
.withArgument("job", "Conversion job: xauth / crazylogin / rakamak / " + .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / " +
"royalauth / vauth / sqlitetosql", false) "royalauth / vauth / sqlitetosql", false)
.permissions(OP_ONLY, AdminPermission.CONVERTER) .permission(AdminPermission.CONVERTER)
.executableCommand(new ConverterCommand()) .executableCommand(ConverterCommand.class)
.build(); .build();
// Register the base login command // Register the base login command
final CommandDescription LOGIN_BASE = CommandDescription.builder() final CommandDescription LOGIN_BASE = CommandDescription.builder()
.parent(null) .parent(null)
.labels("login", "l") .labels("login", "l", "log")
.description("Login command") .description("Login command")
.detailedDescription("Command to log in using AuthMeReloaded.") .detailedDescription("Command to log in using AuthMeReloaded.")
.withArgument("password", "Login password", false) .withArgument("password", "Login password", false)
.permissions(ALLOWED, PlayerPermission.LOGIN) .permission(PlayerPermission.LOGIN)
.executableCommand(new LoginCommand()) .executableCommand(LoginCommand.class)
.build(); .build();
// Register the base logout command // Register the base logout command
@ -296,8 +304,8 @@ public final class CommandInitializer {
.labels("logout") .labels("logout")
.description("Logout command") .description("Logout command")
.detailedDescription("Command to logout using AuthMeReloaded.") .detailedDescription("Command to logout using AuthMeReloaded.")
.permissions(ALLOWED, PlayerPermission.LOGOUT) .permission(PlayerPermission.LOGOUT)
.executableCommand(new LogoutCommand()) .executableCommand(LogoutCommand.class)
.build(); .build();
// Register the base register command // Register the base register command
@ -308,19 +316,19 @@ public final class CommandInitializer {
.detailedDescription("Command to register using AuthMeReloaded.") .detailedDescription("Command to register using AuthMeReloaded.")
.withArgument("password", "Password", true) .withArgument("password", "Password", true)
.withArgument("verifyPassword", "Verify password", true) .withArgument("verifyPassword", "Verify password", true)
.permissions(ALLOWED, PlayerPermission.REGISTER) .permission(PlayerPermission.REGISTER)
.executableCommand(new RegisterCommand()) .executableCommand(RegisterCommand.class)
.build(); .build();
// Register the base unregister command // Register the base unregister command
CommandDescription UNREGISTER_BASE = CommandDescription.builder() CommandDescription UNREGISTER_BASE = CommandDescription.builder()
.parent(null) .parent(null)
.labels("unreg", "unregister") .labels("unregister", "unreg")
.description("Unregistration Command") .description("Unregistration Command")
.detailedDescription("Command to unregister using AuthMeReloaded.") .detailedDescription("Command to unregister using AuthMeReloaded.")
.withArgument("password", "Password", false) .withArgument("password", "Password", false)
.permissions(ALLOWED, PlayerPermission.UNREGISTER) .permission(PlayerPermission.UNREGISTER)
.executableCommand(new UnregisterCommand()) .executableCommand(UnregisterCommand.class)
.build(); .build();
// Register the base changepassword command // Register the base changepassword command
@ -331,17 +339,17 @@ public final class CommandInitializer {
.detailedDescription("Command to change your password using AuthMeReloaded.") .detailedDescription("Command to change your password using AuthMeReloaded.")
.withArgument("oldPassword", "Old Password", false) .withArgument("oldPassword", "Old Password", false)
.withArgument("newPassword", "New Password.", false) .withArgument("newPassword", "New Password.", false)
.permissions(ALLOWED, PlayerPermission.CHANGE_PASSWORD) .permission(PlayerPermission.CHANGE_PASSWORD)
.executableCommand(new ChangePasswordCommand()) .executableCommand(ChangePasswordCommand.class)
.build(); .build();
// Register the base Email command // Register the base Email command
CommandDescription EMAIL_BASE = CommandDescription.builder() CommandDescription EMAIL_BASE = CommandDescription.builder()
.parent(null) .parent(null)
.labels("email", "mail") .labels("email")
.description("Email command") .description("Email command")
.detailedDescription("The AuthMeReloaded Email command base.") .detailedDescription("The AuthMeReloaded Email command base.")
.executableCommand(new EmailBaseCommand()) .executableCommand(EmailBaseCommand.class)
.build(); .build();
// Register the add command // Register the add command
@ -352,8 +360,8 @@ public final class CommandInitializer {
.detailedDescription("Add a new email address to your account.") .detailedDescription("Add a new email address to your account.")
.withArgument("email", "Email address", false) .withArgument("email", "Email address", false)
.withArgument("verifyEmail", "Email address verification", false) .withArgument("verifyEmail", "Email address verification", false)
.permissions(ALLOWED, PlayerPermission.ADD_EMAIL) .permission(PlayerPermission.ADD_EMAIL)
.executableCommand(new AddEmailCommand()) .executableCommand(AddEmailCommand.class)
.build(); .build();
// Register the change command // Register the change command
@ -364,8 +372,8 @@ public final class CommandInitializer {
.detailedDescription("Change an email address of your account.") .detailedDescription("Change an email address of your account.")
.withArgument("oldEmail", "Old email address", false) .withArgument("oldEmail", "Old email address", false)
.withArgument("newEmail", "New email address", false) .withArgument("newEmail", "New email address", false)
.permissions(ALLOWED, PlayerPermission.CHANGE_EMAIL) .permission(PlayerPermission.CHANGE_EMAIL)
.executableCommand(new ChangeEmailCommand()) .executableCommand(ChangeEmailCommand.class)
.build(); .build();
// Register the recover command // Register the recover command
@ -376,19 +384,19 @@ public final class CommandInitializer {
.detailedDescription("Recover your account using an Email address by sending a mail containing " + .detailedDescription("Recover your account using an Email address by sending a mail containing " +
"a new password.") "a new password.")
.withArgument("email", "Email address", false) .withArgument("email", "Email address", false)
.permissions(ALLOWED, PlayerPermission.RECOVER_EMAIL) .permission(PlayerPermission.RECOVER_EMAIL)
.executableCommand(new RecoverEmailCommand()) .executableCommand(RecoverEmailCommand.class)
.build(); .build();
// Register the base captcha command // Register the base captcha command
CommandDescription CAPTCHA_BASE = CommandDescription.builder() CommandDescription CAPTCHA_BASE = CommandDescription.builder()
.parent(null) .parent(null)
.labels("captcha", "capt") .labels("captcha")
.description("Captcha Command") .description("Captcha Command")
.detailedDescription("Captcha command for AuthMeReloaded.") .detailedDescription("Captcha command for AuthMeReloaded.")
.withArgument("captcha", "The Captcha", false) .withArgument("captcha", "The Captcha", false)
.permissions(ALLOWED, PlayerPermission.CAPTCHA) .permission(PlayerPermission.CAPTCHA)
.executableCommand(new CaptchaCommand()) .executableCommand(CaptchaCommand.class)
.build(); .build();
Set<CommandDescription> baseCommands = ImmutableSet.of( Set<CommandDescription> baseCommands = ImmutableSet.of(
@ -402,16 +410,15 @@ public final class CommandInitializer {
CAPTCHA_BASE); CAPTCHA_BASE);
setHelpOnAllBases(baseCommands); setHelpOnAllBases(baseCommands);
return baseCommands; commands = baseCommands;
} }
/** /**
* Set the help command on all base commands, e.g. to register /authme help or /register help. * Sets the help command on all base commands, e.g. to register /authme help or /register help.
* *
* @param commands The list of base commands to register a help child command on * @param commands the list of base commands to register a help child command on
*/ */
private static void setHelpOnAllBases(Collection<CommandDescription> commands) { private void setHelpOnAllBases(Collection<CommandDescription> commands) {
final HelpCommand helpCommandExecutable = new HelpCommand();
final List<String> helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?"); final List<String> helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?");
for (CommandDescription base : commands) { for (CommandDescription base : commands) {
@ -421,7 +428,7 @@ public final class CommandInitializer {
.description("View help") .description("View help")
.detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.") .detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.")
.withArgument("query", "The command or query to view help for.", true) .withArgument("query", "The command or query to view help for.", true)
.executableCommand(helpCommandExecutable) .executableCommand(HelpCommand.class)
.build(); .build();
} }
} }

View File

@ -6,7 +6,9 @@ import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -15,8 +17,7 @@ import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL; import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
/** /**
* The AuthMe command handler, responsible for mapping incoming * Maps incoming command parts to the correct {@link CommandDescription}.
* command parts to the correct {@link CommandDescription}.
*/ */
public class CommandMapper { public class CommandMapper {
@ -28,8 +29,9 @@ public class CommandMapper {
private final Set<CommandDescription> baseCommands; private final Set<CommandDescription> baseCommands;
private final PermissionsManager permissionsManager; private final PermissionsManager permissionsManager;
public CommandMapper(Set<CommandDescription> baseCommands, PermissionsManager permissionsManager) { @Inject
this.baseCommands = baseCommands; public CommandMapper(CommandInitializer commandInitializer, PermissionsManager permissionsManager) {
this.baseCommands = commandInitializer.getCommands();
this.permissionsManager = permissionsManager; this.permissionsManager = permissionsManager;
} }
@ -67,6 +69,23 @@ public class CommandMapper {
return getCommandWithSmallestDifference(base, parts); return getCommandWithSmallestDifference(base, parts);
} }
/**
* Return all {@link ExecutableCommand} classes referenced in {@link CommandDescription} objects.
*
* @return all classes
* @see CommandInitializer#getCommands
*/
public Set<Class<? extends ExecutableCommand>> getCommandClasses() {
Set<Class<? extends ExecutableCommand>> classes = new HashSet<>(50);
for (CommandDescription command : baseCommands) {
classes.add(command.getExecutableCommand());
for (CommandDescription child : command.getChildren()) {
classes.add(child.getExecutableCommand());
}
}
return classes;
}
private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) { private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) {
// Return the base command with incorrect arg count error if we only have one part // Return the base command with incorrect arg count error if we only have one part
if (parts.size() <= 1) { if (parts.size() <= 1) {
@ -139,7 +158,7 @@ public class CommandMapper {
private static FoundCommandResult transformResultForHelp(FoundCommandResult result) { private static FoundCommandResult transformResultForHelp(FoundCommandResult result) {
if (result.getCommandDescription() != null if (result.getCommandDescription() != null
&& HELP_COMMAND_CLASS.isAssignableFrom(result.getCommandDescription().getExecutableCommand().getClass())) { && HELP_COMMAND_CLASS == result.getCommandDescription().getExecutableCommand()) {
// For "/authme help register" we have labels = [authme, help] and arguments = [register] // For "/authme help register" we have labels = [authme, help] and arguments = [register]
// But for the help command we want labels = [authme, help] and arguments = [authme, register], // But for the help command we want labels = [authme, help] and arguments = [authme, register],
// so we can use the arguments as the labels to the command to show help for // so we can use the arguments as the labels to the command to show help for
@ -152,7 +171,7 @@ public class CommandMapper {
} }
private FoundResultStatus getPermissionAwareStatus(CommandSender sender, CommandDescription command) { private FoundResultStatus getPermissionAwareStatus(CommandSender sender, CommandDescription command) {
if (sender != null && !permissionsManager.hasPermission(sender, command)) { if (sender != null && !permissionsManager.hasPermission(sender, command.getPermission())) {
return FoundResultStatus.NO_PERMISSION; return FoundResultStatus.NO_PERMISSION;
} }
return FoundResultStatus.SUCCESS; return FoundResultStatus.SUCCESS;

View File

@ -1,52 +0,0 @@
package fr.xephi.authme.command;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode;
import java.util.List;
/**
*/
public class CommandPermissions {
/**
* Defines the permission nodes required to have permission to execute this command.
*/
private List<PermissionNode> permissionNodes;
/**
* Defines the default permission if the permission nodes couldn't be used.
*/
private DefaultPermission defaultPermission;
/**
* Constructor.
*
* @param permissionNodes The permission nodes required to execute a command.
* @param defaultPermission The default permission if the permission nodes couldn't be used.
*/
public CommandPermissions(List<PermissionNode> permissionNodes, DefaultPermission defaultPermission) {
this.permissionNodes = permissionNodes;
this.defaultPermission = defaultPermission;
}
/**
* Get the permission nodes required to execute this command.
*
* @return The permission nodes required to execute this command.
*/
public List<PermissionNode> getPermissionNodes() {
return this.permissionNodes;
}
/**
* Get the default permission if the permission nodes couldn't be used.
*
* @return The default permission.
*/
public DefaultPermission getDefaultPermission() {
return this.defaultPermission;
}
}

View File

@ -1,26 +1,13 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.AntiBot;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.ValidationService; import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Collection; import javax.inject.Inject;
import java.util.List;
/** /**
* Service for implementations of {@link ExecutableCommand} to execute some common tasks. * Service for implementations of {@link ExecutableCommand} to execute some common tasks.
@ -28,39 +15,12 @@ import java.util.List;
*/ */
public class CommandService { public class CommandService {
private final AuthMe authMe; @Inject
private final Messages messages; private Messages messages;
private final HelpProvider helpProvider; @Inject
private final CommandMapper commandMapper; private NewSetting settings;
private final PasswordSecurity passwordSecurity; @Inject
private final PermissionsManager permissionsManager; private ValidationService validationService;
private final NewSetting settings;
private final PluginHooks pluginHooks;
private final SpawnLoader spawnLoader;
private final AntiBot antiBot;
private final ValidationService validationService;
private final BukkitService bukkitService;
/*
* Constructor.
*/
public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages,
PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings,
PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot,
ValidationService validationService, BukkitService bukkitService) {
this.authMe = authMe;
this.messages = messages;
this.helpProvider = helpProvider;
this.commandMapper = commandMapper;
this.passwordSecurity = passwordSecurity;
this.permissionsManager = permissionsManager;
this.settings = settings;
this.pluginHooks = pluginHooks;
this.spawnLoader = spawnLoader;
this.antiBot = antiBot;
this.validationService = validationService;
this.bukkitService = bukkitService;
}
/** /**
* Send a message to a player. * Send a message to a player.
@ -83,86 +43,6 @@ public class CommandService {
messages.send(sender, messageKey, replacements); messages.send(sender, messageKey, replacements);
} }
/**
* Map command parts to a command description.
*
* @param sender The command sender issuing the request (for permission check), or null to skip permissions
* @param commandParts The received command parts to map to a command
* @return The computed mapping result
*/
public FoundCommandResult mapPartsToCommand(CommandSender sender, List<String> commandParts) {
return commandMapper.mapPartsToCommand(sender, commandParts);
}
/**
* Run the given task asynchronously with the Bukkit scheduler.
*
* @param task The task to run
*/
public void runTaskAsynchronously(Runnable task) {
authMe.getServer().getScheduler().runTaskAsynchronously(authMe, task);
}
/**
* Return the AuthMe data source.
*
* @return The used data source
*/
public DataSource getDataSource() {
return authMe.getDataSource();
}
/**
* Return the AuthMe instance for further manipulation. Use only if other methods from
* the command service cannot be used.
*
* @return The AuthMe instance
*/
public AuthMe getAuthMe() {
return authMe;
}
/**
* Return the PasswordSecurity instance.
*
* @return The password security instance
*/
public PasswordSecurity getPasswordSecurity() {
return passwordSecurity;
}
/**
* Output the help for a given command.
*
* @param sender The sender to output the help to
* @param result The result to output information about
* @param options Output options, see {@link HelpProvider}
*/
public void outputHelp(CommandSender sender, FoundCommandResult result, int options) {
List<String> lines = helpProvider.printHelp(sender, result, options);
for (String line : lines) {
sender.sendMessage(line);
}
}
/**
* Return the management instance of the plugin.
*
* @return The Management instance linked to the AuthMe instance
*/
public Management getManagement() {
return authMe.getManagement();
}
/**
* Return the permissions manager.
*
* @return the permissions manager
*/
public PermissionsManager getPermissionsManager() {
return permissionsManager;
}
/** /**
* Retrieve a message by its message key. * Retrieve a message by its message key.
* *
@ -193,33 +73,6 @@ public class CommandService {
return settings; return settings;
} }
public PlayerCache getPlayerCache() {
return PlayerCache.getInstance();
}
public PluginHooks getPluginHooks() {
return pluginHooks;
}
public SpawnLoader getSpawnLoader() {
return spawnLoader;
}
public AntiBot getAntiBot() {
return antiBot;
}
/**
* Verifies whether a password is valid according to the plugin settings.
*
* @param password the password to verify
* @param username the username the password is associated with
* @return message key with the password error, or {@code null} if password is valid
*/
public MessageKey validatePassword(String password, String username) {
return validationService.validatePassword(password, username);
}
public boolean validateEmail(String email) { public boolean validateEmail(String email) {
return validationService.validateEmail(email); return validationService.validateEmail(email);
} }
@ -228,16 +81,4 @@ public class CommandService {
return validationService.isEmailFreeForRegistration(email, sender); return validationService.isEmailFreeForRegistration(email, sender);
} }
public Player getPlayer(String name) {
return bukkitService.getPlayerExact(name);
}
public Collection<? extends Player> getOnlinePlayers() {
return bukkitService.getOnlinePlayers();
}
public BukkitService getBukkitService() {
return bukkitService;
}
} }

View File

@ -10,12 +10,11 @@ import java.util.List;
public interface ExecutableCommand { public interface ExecutableCommand {
/** /**
* Execute the command with the given arguments. * Executes the command with the given arguments.
* *
* @param sender The command sender. * @param sender the command sender (initiator of the command)
* @param arguments The arguments. * @param arguments the arguments
* @param commandService The command service.
*/ */
void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService); void executeCommand(CommandSender sender, List<String> arguments);
} }

View File

@ -1,19 +1,19 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import java.util.List;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.List;
/** /**
* Common base type for player-only commands, handling the verification that the command sender is indeed a player. * Common base type for player-only commands, handling the verification that the command sender is indeed a player.
*/ */
public abstract class PlayerCommand implements ExecutableCommand { public abstract class PlayerCommand implements ExecutableCommand {
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
if (sender instanceof Player) { if (sender instanceof Player) {
runCommand((Player) sender, arguments, commandService); runCommand((Player) sender, arguments);
} else { } else {
String alternative = getAlternativeCommand(); String alternative = getAlternativeCommand();
if (alternative != null) { if (alternative != null) {
@ -25,19 +25,18 @@ public abstract class PlayerCommand implements ExecutableCommand {
} }
/** /**
* Run the command with the given player and arguments. * Runs the command with the given player and arguments.
* *
* @param player The player who initiated the command * @param player the player who initiated the command
* @param arguments The arguments supplied with the command * @param arguments the arguments supplied with the command
* @param commandService The command service
*/ */
protected abstract void runCommand(Player player, List<String> arguments, CommandService commandService); protected abstract void runCommand(Player player, List<String> arguments);
/** /**
* Return an alternative command (textual representation) that is not restricted to players only. * Returns an alternative command (textual representation) that is not restricted to players only.
* Example: {@code "authme register <playerName> <password>"} * Example: {@code "/authme register <playerName> <password>"}
* *
* @return Alternative command not only for players, or null if not applicable * @return Alternative command not restricted to players, or null if not applicable
*/ */
protected String getAlternativeCommand() { protected String getAlternativeCommand() {
return null; return null;

View File

@ -1,6 +1,6 @@
package fr.xephi.authme.command.executable; package fr.xephi.authme.command.executable;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandMapper;
import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
@ -9,6 +9,7 @@ import fr.xephi.authme.command.help.HelpProvider;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND; import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
@ -16,11 +17,18 @@ import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
public class HelpCommand implements ExecutableCommand { public class HelpCommand implements ExecutableCommand {
@Inject
private CommandMapper commandMapper;
@Inject
private HelpProvider helpProvider;
// Convention: arguments is not the actual invoked arguments but the command that was invoked, // Convention: arguments is not the actual invoked arguments but the command that was invoked,
// e.g. "/authme help register" would typically be arguments = [register], but here we pass [authme, register] // e.g. "/authme help register" would typically be arguments = [register], but here we pass [authme, register]
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
FoundCommandResult result = commandService.mapPartsToCommand(sender, arguments); FoundCommandResult result = commandMapper.mapPartsToCommand(sender, arguments);
FoundResultStatus resultStatus = result.getResultStatus(); FoundResultStatus resultStatus = result.getResultStatus();
if (MISSING_BASE_COMMAND.equals(resultStatus)) { if (MISSING_BASE_COMMAND.equals(resultStatus)) {
@ -38,9 +46,9 @@ public class HelpCommand implements ExecutableCommand {
int mappedCommandLevel = result.getCommandDescription().getLabelCount(); int mappedCommandLevel = result.getCommandDescription().getLabelCount();
if (mappedCommandLevel == 1) { if (mappedCommandLevel == 1) {
commandService.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN); helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN);
} else { } else {
commandService.outputHelp(sender, result, HelpProvider.ALL_OPTIONS); helpProvider.outputHelp(sender, result, HelpProvider.ALL_OPTIONS);
} }
} }

View File

@ -3,10 +3,13 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -14,25 +17,27 @@ import java.util.List;
*/ */
public class AccountsCommand implements ExecutableCommand { public class AccountsCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private BukkitService bukkitService;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, public void executeCommand(final CommandSender sender, List<String> arguments) {
final CommandService commandService) {
final String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); final String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
// Assumption: a player name cannot contain '.' // Assumption: a player name cannot contain '.'
if (!playerName.contains(".")) { if (playerName.contains(".")) {
commandService.runTaskAsynchronously(new Runnable() { bukkitService.runTaskAsynchronously(new Runnable() {
@Override @Override
public void run() { public void run() {
PlayerAuth auth = commandService.getDataSource().getAuth(playerName.toLowerCase()); List<String> accountList = dataSource.getAllAuthsByIp(playerName);
if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
List<String> accountList = commandService.getDataSource().getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) { if (accountList.isEmpty()) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED); sender.sendMessage("[AuthMe] This IP does not exist in the database.");
} else if (accountList.size() == 1) { } else if (accountList.size() == 1) {
sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
} else { } else {
@ -41,12 +46,18 @@ public class AccountsCommand implements ExecutableCommand {
} }
}); });
} else { } else {
commandService.runTaskAsynchronously(new Runnable() { bukkitService.runTaskAsynchronously(new Runnable() {
@Override @Override
public void run() { public void run() {
List<String> accountList = commandService.getDataSource().getAllAuthsByIp(playerName); PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase());
if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
List<String> accountList = dataSource.getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) { if (accountList.isEmpty()) {
sender.sendMessage("[AuthMe] This IP does not exist in the database."); commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
} else if (accountList.size() == 1) { } else if (accountList.size() == 1) {
sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
} else { } else {

View File

@ -1,7 +1,6 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -14,7 +13,7 @@ import java.util.List;
public class AuthMeCommand implements ExecutableCommand { public class AuthMeCommand implements ExecutableCommand {
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
sender.sendMessage(ChatColor.GREEN + "This server is running " + AuthMe.getPluginName() + " v" sender.sendMessage(ChatColor.GREEN + "This server is running " + AuthMe.getPluginName() + " v"
+ AuthMe.getPluginVersion() + " b" + AuthMe.getPluginBuildNumber()+ "! " + ChatColor.RED + "<3"); + AuthMe.getPluginVersion() + " b" + AuthMe.getPluginBuildNumber()+ "! " + ChatColor.RED + "<3");
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/authme help" + ChatColor.YELLOW sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/authme help" + ChatColor.YELLOW

View File

@ -2,13 +2,19 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.ValidationService;
import fr.xephi.authme.util.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -16,30 +22,46 @@ import java.util.List;
*/ */
public class ChangePasswordAdminCommand implements ExecutableCommand { public class ChangePasswordAdminCommand implements ExecutableCommand {
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private PlayerCache playerCache;
@Inject
private DataSource dataSource;
@Inject
private BukkitService bukkitService;
@Inject
private ValidationService validationService;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, public void executeCommand(final CommandSender sender, List<String> arguments) {
final CommandService commandService) {
// Get the player and password // Get the player and password
final String playerName = arguments.get(0); final String playerName = arguments.get(0);
final String playerPass = arguments.get(1); final String playerPass = arguments.get(1);
// Validate the password // Validate the password
MessageKey passwordError = commandService.validatePassword(playerPass, playerName); ValidationResult validationResult = validationService.validatePassword(playerPass, playerName);
if (passwordError != null) { if (validationResult.hasError()) {
commandService.send(sender, passwordError); commandService.send(sender, validationResult.getMessageKey(), validationResult.getArgs());
return; return;
} }
// Set the password // Set the password
final String playerNameLowerCase = playerName.toLowerCase(); final String playerNameLowerCase = playerName.toLowerCase();
commandService.runTaskAsynchronously(new Runnable() { bukkitService.runTaskAsynchronously(new Runnable() {
@Override @Override
public void run() { public void run() {
DataSource dataSource = commandService.getDataSource();
PlayerAuth auth = null; PlayerAuth auth = null;
if (commandService.getPlayerCache().isAuthenticated(playerNameLowerCase)) { if (playerCache.isAuthenticated(playerNameLowerCase)) {
auth = commandService.getPlayerCache().getAuth(playerNameLowerCase); auth = playerCache.getAuth(playerNameLowerCase);
} else if (dataSource.isAuthAvailable(playerNameLowerCase)) { } else if (dataSource.isAuthAvailable(playerNameLowerCase)) {
auth = dataSource.getAuth(playerNameLowerCase); auth = dataSource.getAuth(playerNameLowerCase);
} }
@ -48,15 +70,14 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
return; return;
} }
HashedPassword hashedPassword = commandService.getPasswordSecurity() HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase);
.computeHash(playerPass, playerNameLowerCase);
auth.setPassword(hashedPassword); auth.setPassword(hashedPassword);
if (!dataSource.updatePassword(auth)) { if (dataSource.updatePassword(auth)) {
commandService.send(sender, MessageKey.ERROR);
} else {
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(playerNameLowerCase + "'s password changed"); ConsoleLogger.info(playerNameLowerCase + "'s password changed");
} else {
commandService.send(sender, MessageKey.ERROR);
} }
} }

View File

@ -1,6 +1,6 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.converter.Converter; import fr.xephi.authme.converter.Converter;
@ -10,18 +10,30 @@ import fr.xephi.authme.converter.RoyalAuthConverter;
import fr.xephi.authme.converter.SqliteToSql; import fr.xephi.authme.converter.SqliteToSql;
import fr.xephi.authme.converter.vAuthConverter; import fr.xephi.authme.converter.vAuthConverter;
import fr.xephi.authme.converter.xAuthConverter; import fr.xephi.authme.converter.xAuthConverter;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/**
* Converter command: launches conversion based on its parameters.
*/
public class ConverterCommand implements ExecutableCommand { public class ConverterCommand implements ExecutableCommand {
@Override @Inject
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { private CommandService commandService;
// AuthMe plugin instance
final AuthMe plugin = AuthMe.getInstance();
@Inject
private BukkitService bukkitService;
@Inject
private AuthMeServiceInitializer initializer;
@Override
public void executeCommand(final CommandSender sender, List<String> arguments) {
// Get the conversion job // Get the conversion job
String job = arguments.get(0); String job = arguments.get(0);
@ -33,49 +45,35 @@ public class ConverterCommand implements ExecutableCommand {
} }
// Get the proper converter instance // Get the proper converter instance
Converter converter = null; final Converter converter = initializer.newInstance(jobType.getConverterClass());
switch (jobType) {
case XAUTH:
converter = new xAuthConverter(plugin, sender);
break;
case CRAZYLOGIN:
converter = new CrazyLoginConverter(plugin, sender);
break;
case RAKAMAK:
converter = new RakamakConverter(plugin, sender);
break;
case ROYALAUTH:
converter = new RoyalAuthConverter(plugin);
break;
case VAUTH:
converter = new vAuthConverter(plugin, sender);
break;
case SQLITETOSQL:
converter = new SqliteToSql(plugin, sender, commandService.getSettings());
break;
default:
break;
}
// Run the convert job // Run the convert job
commandService.runTaskAsynchronously(converter); bukkitService.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
converter.execute(sender);
}
});
// Show a status message // Show a status message
sender.sendMessage("[AuthMe] Successfully converted from " + jobType.getName()); sender.sendMessage("[AuthMe] Successfully converted from " + jobType.getName());
} }
public enum ConvertType { @VisibleForTesting
XAUTH("xauth"), enum ConvertType {
CRAZYLOGIN("crazylogin"), XAUTH("xauth", xAuthConverter.class),
RAKAMAK("rakamak"), CRAZYLOGIN("crazylogin", CrazyLoginConverter.class),
ROYALAUTH("royalauth"), RAKAMAK("rakamak", RakamakConverter.class),
VAUTH("vauth"), ROYALAUTH("royalauth", RoyalAuthConverter.class),
SQLITETOSQL("sqlitetosql"); VAUTH("vauth", vAuthConverter.class),
SQLITETOSQL("sqlitetosql", SqliteToSql.class);
final String name; private final String name;
private final Class<? extends Converter> converterClass;
ConvertType(String name) { ConvertType(String name, Class<? extends Converter> converterClass) {
this.name = name; this.name = name;
this.converterClass = converterClass;
} }
public static ConvertType fromName(String name) { public static ConvertType fromName(String name) {
@ -87,8 +85,12 @@ public class ConverterCommand implements ExecutableCommand {
return null; return null;
} }
String getName() { public String getName() {
return this.name; return this.name;
} }
public Class<? extends Converter> getConverterClass() {
return converterClass;
}
} }
} }

View File

@ -1,9 +1,10 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.settings.SpawnLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -11,12 +12,15 @@ import java.util.List;
*/ */
public class FirstSpawnCommand extends PlayerCommand { public class FirstSpawnCommand extends PlayerCommand {
@Inject
private SpawnLoader spawnLoader;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
if (commandService.getSpawnLoader().getFirstSpawn() != null) { if (spawnLoader.getFirstSpawn() == null) {
player.teleport(commandService.getSpawnLoader().getFirstSpawn());
} else {
player.sendMessage("[AuthMe] First spawn has failed, please try to define the first spawn"); player.sendMessage("[AuthMe] First spawn has failed, please try to define the first spawn");
} else {
player.teleport(spawnLoader.getFirstSpawn());
} }
} }
} }

View File

@ -1,10 +1,13 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
import static fr.xephi.authme.permission.PlayerPermission.CAN_LOGIN_BE_FORCED; import static fr.xephi.authme.permission.PlayerPermission.CAN_LOGIN_BE_FORCED;
@ -14,18 +17,27 @@ import static fr.xephi.authme.permission.PlayerPermission.CAN_LOGIN_BE_FORCED;
*/ */
public class ForceLoginCommand implements ExecutableCommand { public class ForceLoginCommand implements ExecutableCommand {
@Inject
private PermissionsManager permissionsManager;
@Inject
private Management management;
@Inject
private BukkitService bukkitService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the player query // Get the player query
String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
Player player = commandService.getPlayer(playerName); Player player = bukkitService.getPlayerExact(playerName);
if (player == null || !player.isOnline()) { if (player == null || !player.isOnline()) {
sender.sendMessage("Player needs to be online!"); sender.sendMessage("Player needs to be online!");
} else if (!commandService.getPermissionsManager().hasPermission(player, CAN_LOGIN_BE_FORCED)) { } else if (!permissionsManager.hasPermission(player, CAN_LOGIN_BE_FORCED)) {
sender.sendMessage("You cannot force login the player " + playerName + "!"); sender.sendMessage("You cannot force login the player " + playerName + "!");
} else { } else {
commandService.getManagement().performLogin(player, "dontneed", true); management.performLogin(player, "dontneed", true);
sender.sendMessage("Force login for " + playerName + " performed!"); sender.sendMessage("Force login for " + playerName + " performed!");
} }
} }

View File

@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -13,11 +15,17 @@ import java.util.List;
*/ */
public class GetEmailCommand implements ExecutableCommand { public class GetEmailCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
PlayerAuth auth = commandService.getDataSource().getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commandService.send(sender, MessageKey.UNKNOWN_USER);
} else { } else {

View File

@ -1,20 +1,24 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class GetIpCommand implements ExecutableCommand { public class GetIpCommand implements ExecutableCommand {
@Inject
private BukkitService bukkitService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the player query // Get the player query
String playerName = arguments.get(0); String playerName = arguments.get(0);
Player player = commandService.getPlayer(playerName); Player player = bukkitService.getPlayerExact(playerName);
if (player == null) { if (player == null) {
sender.sendMessage("The player is not online"); sender.sendMessage("The player is not online");
return; return;

View File

@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -14,12 +16,18 @@ import java.util.List;
*/ */
public class LastLoginCommand implements ExecutableCommand { public class LastLoginCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the player // Get the player
String playerName = (arguments.size() >= 1) ? arguments.get(0) : sender.getName(); String playerName = (arguments.size() >= 1) ? arguments.get(0) : sender.getName();
PlayerAuth auth = commandService.getDataSource().getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED); commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
return; return;

View File

@ -1,14 +1,18 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.task.PurgeTask;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.ArrayList; import javax.inject.Inject;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* Command for purging data of banned players. Depending on the settings * Command for purging data of banned players. Depending on the settings
@ -16,30 +20,30 @@ import java.util.List;
*/ */
public class PurgeBannedPlayersCommand implements ExecutableCommand { public class PurgeBannedPlayersCommand implements ExecutableCommand {
@Override @Inject
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { private DataSource dataSource;
// AuthMe plugin instance
final AuthMe plugin = commandService.getAuthMe();
@Inject
private AuthMe plugin;
@Inject
private BukkitService bukkitService;
@Override
public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the list of banned players // Get the list of banned players
List<String> bannedPlayers = new ArrayList<>(); Set<String> namedBanned = new HashSet<>();
for (OfflinePlayer offlinePlayer : plugin.getServer().getBannedPlayers()) { Set<OfflinePlayer> bannedPlayers = bukkitService.getBannedPlayers();
bannedPlayers.add(offlinePlayer.getName().toLowerCase()); for (OfflinePlayer offlinePlayer : bannedPlayers) {
namedBanned.add(offlinePlayer.getName().toLowerCase());
} }
//todo: note this should may run async because it may executes a SQL-Query
// Purge the banned players // Purge the banned players
commandService.getDataSource().purgeBanned(bannedPlayers); dataSource.purgeBanned(namedBanned);
if (commandService.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES)
&& commandService.getPluginHooks().isEssentialsAvailable())
plugin.dataManager.purgeEssentials(bannedPlayers);
if (commandService.getProperty(PurgeSettings.REMOVE_PLAYER_DAT))
plugin.dataManager.purgeDat(bannedPlayers);
if (commandService.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES))
plugin.dataManager.purgeLimitedCreative(bannedPlayers);
if (commandService.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE))
plugin.dataManager.purgeAntiXray(bannedPlayers);
// Show a status message // Show a status message
sender.sendMessage("[AuthMe] Database has been purged correctly"); sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
new PurgeTask(plugin, sender, namedBanned, bannedPlayers).runTaskTimer(plugin, 0, 1);
} }
} }

View File

@ -1,14 +1,16 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.task.PurgeTask;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* Command for purging the data of players which have not been since for a given number * Command for purging the data of players which have not been since for a given number
@ -18,8 +20,14 @@ public class PurgeCommand implements ExecutableCommand {
private static final int MINIMUM_LAST_SEEN_DAYS = 30; private static final int MINIMUM_LAST_SEEN_DAYS = 30;
@Inject
private DataSource dataSource;
@Inject
private AuthMe plugin;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the days parameter // Get the days parameter
String daysStr = arguments.get(0); String daysStr = arguments.get(0);
@ -44,25 +52,13 @@ public class PurgeCommand implements ExecutableCommand {
calendar.add(Calendar.DATE, -days); calendar.add(Calendar.DATE, -days);
long until = calendar.getTimeInMillis(); long until = calendar.getTimeInMillis();
//todo: note this should may run async because it may executes a SQL-Query
// Purge the data, get the purged values // Purge the data, get the purged values
List<String> purged = commandService.getDataSource().autoPurgeDatabase(until); Set<String> purged = dataSource.autoPurgeDatabase(until);
// Show a status message // Show a status message
sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts"); sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts");
sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
// Purge other data new PurgeTask(plugin, sender, purged).runTaskTimer(plugin, 0, 1);
AuthMe plugin = commandService.getAuthMe();
if (commandService.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES) &&
commandService.getPluginHooks().isEssentialsAvailable())
plugin.dataManager.purgeEssentials(purged);
if (commandService.getProperty(PurgeSettings.REMOVE_PLAYER_DAT))
plugin.dataManager.purgeDat(purged);
if (commandService.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES))
plugin.dataManager.purgeLimitedCreative(purged);
if (commandService.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE))
plugin.dataManager.purgeAntiXray(purged);
// Show a status message
sender.sendMessage(ChatColor.GREEN + "[AuthMe] Database has been purged correctly");
} }
} }

View File

@ -3,9 +3,11 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -13,26 +15,32 @@ import java.util.List;
*/ */
public class PurgeLastPositionCommand implements ExecutableCommand { public class PurgeLastPositionCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(final CommandSender sender, List<String> arguments) {
String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
if ("*".equals(playerName)) { if ("*".equals(playerName)) {
for (PlayerAuth auth : commandService.getDataSource().getAllAuths()) { for (PlayerAuth auth : dataSource.getAllAuths()) {
resetLastPosition(auth); resetLastPosition(auth);
commandService.getDataSource().updateQuitLoc(auth); dataSource.updateQuitLoc(auth);
} }
sender.sendMessage("All players last position locations are now reset"); sender.sendMessage("All players last position locations are now reset");
} else { } else {
// Get the user auth and make sure the user exists // Get the user auth and make sure the user exists
PlayerAuth auth = commandService.getDataSource().getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commandService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }
resetLastPosition(auth); resetLastPosition(auth);
commandService.getDataSource().updateQuitLoc(auth); dataSource.updateQuitLoc(auth);
sender.sendMessage(playerName + "'s last position location is now reset"); sender.sendMessage(playerName + "'s last position location is now reset");
} }
} }

View File

@ -1,68 +1,85 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.ValidationService;
import fr.xephi.authme.util.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
/** /**
* Admin command to register a user. * Admin command to register a user.
*/ */
public class RegisterAdminCommand implements ExecutableCommand { public class RegisterAdminCommand implements ExecutableCommand {
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private CommandService commandService;
@Inject
private DataSource dataSource;
@Inject
private BukkitService bukkitService;
@Inject
private ValidationService validationService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, public void executeCommand(final CommandSender sender, List<String> arguments) {
final CommandService commandService) {
// Get the player name and password // Get the player name and password
final String playerName = arguments.get(0); final String playerName = arguments.get(0);
final String playerPass = arguments.get(1); final String playerPass = arguments.get(1);
final String playerNameLowerCase = playerName.toLowerCase(); final String playerNameLowerCase = playerName.toLowerCase();
// Command logic // Command logic
MessageKey passwordError = commandService.validatePassword(playerPass, playerName); ValidationResult passwordValidation = validationService.validatePassword(playerPass, playerName);
if (passwordError != null) { if (passwordValidation.hasError()) {
commandService.send(sender, passwordError); commandService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return; return;
} }
commandService.runTaskAsynchronously(new Runnable() { bukkitService.runTaskAsynchronously(new Runnable() {
@Override @Override
public void run() { public void run() {
if (commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) { if (dataSource.isAuthAvailable(playerNameLowerCase)) {
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
return; return;
} }
HashedPassword hashedPassword = commandService.getPasswordSecurity() HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase);
.computeHash(playerPass, playerNameLowerCase);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(playerNameLowerCase) .name(playerNameLowerCase)
.realName(playerName) .realName(playerName)
.password(hashedPassword) .password(hashedPassword)
.build(); .build();
if (!commandService.getDataSource().saveAuth(auth)) { if (!dataSource.saveAuth(auth)) {
commandService.send(sender, MessageKey.ERROR); commandService.send(sender, MessageKey.ERROR);
return; return;
} }
commandService.getDataSource().setUnlogged(playerNameLowerCase); dataSource.setUnlogged(playerNameLowerCase);
commandService.send(sender, MessageKey.REGISTER_SUCCESS); commandService.send(sender, MessageKey.REGISTER_SUCCESS);
ConsoleLogger.info(sender.getName() + " registered " + playerName); ConsoleLogger.info(sender.getName() + " registered " + playerName);
Player player = commandService.getPlayer(playerName); final Player player = bukkitService.getPlayerExact(playerName);
if (player != null) { if (player != null) {
final Player p = player; bukkitService.scheduleSyncDelayedTask(new Runnable() {
p.getServer().getScheduler().scheduleSyncDelayedTask(commandService.getAuthMe(), new Runnable() {
@Override @Override
public void run() { public void run() {
p.kickPlayer("An admin just registered you, please log in again"); player.kickPlayer("An admin just registered you, please log in again");
} }
}); });
} }

View File

@ -4,9 +4,14 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -14,11 +19,32 @@ import java.util.List;
*/ */
public class ReloadCommand implements ExecutableCommand { public class ReloadCommand implements ExecutableCommand {
@Inject
private AuthMe plugin;
@Inject
private AuthMeServiceInitializer initializer;
@Inject
private NewSetting settings;
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
AuthMe plugin = commandService.getAuthMe();
try { try {
plugin.reload(); settings.reload();
ConsoleLogger.setLoggingOptions(settings);
// We do not change database type for consistency issues, but we'll output a note in the logs
if (!settings.getProperty(DatabaseSettings.BACKEND).equals(dataSource.getType())) {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
sender.sendMessage("Note: cannot change database type during /authme reload");
}
initializer.performReloadOnServices();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) { } catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting"); sender.sendMessage("Error occurred during reload of AuthMe: aborting");

View File

@ -6,8 +6,10 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -15,9 +17,20 @@ import java.util.List;
*/ */
public class SetEmailCommand implements ExecutableCommand { public class SetEmailCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Inject
private PlayerCache playerCache;
@Inject
private BukkitService bukkitService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, public void executeCommand(final CommandSender sender, List<String> arguments) {
final CommandService commandService) {
// Get the player name and email address // Get the player name and email address
final String playerName = arguments.get(0); final String playerName = arguments.get(0);
final String playerEmail = arguments.get(1); final String playerEmail = arguments.get(1);
@ -28,11 +41,10 @@ public class SetEmailCommand implements ExecutableCommand {
return; return;
} }
commandService.runTaskAsynchronously(new Runnable() { bukkitService.runTaskAsynchronously(new Runnable() {
@Override @Override
public void run() { public void run() {
// Validate the user // Validate the user
DataSource dataSource = commandService.getDataSource();
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commandService.send(sender, MessageKey.UNKNOWN_USER);
@ -50,8 +62,8 @@ public class SetEmailCommand implements ExecutableCommand {
} }
// Update the player cache // Update the player cache
if (PlayerCache.getInstance().getAuth(playerName) != null) { if (playerCache.getAuth(playerName) != null) {
PlayerCache.getInstance().updatePlayer(auth); playerCache.updatePlayer(auth);
} }
// Show a status message // Show a status message

View File

@ -1,16 +1,20 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.settings.SpawnLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class SetFirstSpawnCommand extends PlayerCommand { public class SetFirstSpawnCommand extends PlayerCommand {
@Inject
private SpawnLoader spawnLoader;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
if (commandService.getSpawnLoader().setFirstSpawn(player.getLocation())) { if (spawnLoader.setFirstSpawn(player.getLocation())) {
player.sendMessage("[AuthMe] Correctly defined new first spawn point"); player.sendMessage("[AuthMe] Correctly defined new first spawn point");
} else { } else {
player.sendMessage("[AuthMe] SetFirstSpawn has failed, please retry"); player.sendMessage("[AuthMe] SetFirstSpawn has failed, please retry");

View File

@ -1,16 +1,20 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.settings.SpawnLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class SetSpawnCommand extends PlayerCommand { public class SetSpawnCommand extends PlayerCommand {
@Inject
private SpawnLoader spawnLoader;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
if (commandService.getSpawnLoader().setSpawn(player.getLocation())) { if (spawnLoader.setSpawn(player.getLocation())) {
player.sendMessage("[AuthMe] Correctly defined new spawn point"); player.sendMessage("[AuthMe] Correctly defined new spawn point");
} else { } else {
player.sendMessage("[AuthMe] SetSpawn has failed, please retry"); player.sendMessage("[AuthMe] SetSpawn has failed, please retry");

View File

@ -1,19 +1,23 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.settings.SpawnLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class SpawnCommand extends PlayerCommand { public class SpawnCommand extends PlayerCommand {
@Inject
private SpawnLoader spawnLoader;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
if (commandService.getSpawnLoader().getSpawn() != null) { if (spawnLoader.getSpawn() == null) {
player.teleport(commandService.getSpawnLoader().getSpawn());
} else {
player.sendMessage("[AuthMe] Spawn has failed, please try to define the spawn"); player.sendMessage("[AuthMe] Spawn has failed, please try to define the spawn");
} else {
player.teleport(spawnLoader.getSpawn());
} }
} }
} }

View File

@ -1,13 +1,14 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AntiBot; import fr.xephi.authme.AntiBot;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandMapper;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -16,9 +17,17 @@ import java.util.List;
*/ */
public class SwitchAntiBotCommand implements ExecutableCommand { public class SwitchAntiBotCommand implements ExecutableCommand {
@Inject
private AntiBot antiBot;
@Inject
private CommandMapper commandMapper;
@Inject
private HelpProvider helpProvider;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(final CommandSender sender, List<String> arguments) {
AntiBot antiBot = commandService.getAntiBot();
if (arguments.isEmpty()) { if (arguments.isEmpty()) {
sender.sendMessage("[AuthMe] AntiBot status: " + antiBot.getAntiBotStatus().name()); sender.sendMessage("[AuthMe] AntiBot status: " + antiBot.getAntiBotStatus().name());
return; return;
@ -35,8 +44,8 @@ public class SwitchAntiBotCommand implements ExecutableCommand {
sender.sendMessage("[AuthMe] AntiBot Manual Override: disabled!"); sender.sendMessage("[AuthMe] AntiBot Manual Override: disabled!");
} else { } else {
sender.sendMessage(ChatColor.DARK_RED + "Invalid AntiBot mode!"); sender.sendMessage(ChatColor.DARK_RED + "Invalid AntiBot mode!");
FoundCommandResult result = commandService.mapPartsToCommand(sender, Arrays.asList("authme", "antibot")); FoundCommandResult result = commandMapper.mapPartsToCommand(sender, Arrays.asList("authme", "antibot"));
commandService.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS); helpProvider.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS);
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/authme help antibot"); sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/authme help antibot");
} }
} }

View File

@ -1,24 +1,25 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.AuthGroupHandler;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.task.MessageTask; import fr.xephi.authme.task.LimboPlayerTaskManager;
import fr.xephi.authme.task.TimeoutTask;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitTask;
import javax.inject.Inject;
import java.util.List; import java.util.List;
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND; import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
@ -28,31 +29,53 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
*/ */
public class UnregisterAdminCommand implements ExecutableCommand { public class UnregisterAdminCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private CommandService commandService;
@Inject
private PlayerCache playerCache;
@Inject
private BukkitService bukkitService;
@Inject
private LimboCache limboCache;
@Inject
private LimboPlayerTaskManager limboPlayerTaskManager;
@Inject
private AuthGroupHandler authGroupHandler;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(final CommandSender sender, List<String> arguments) {
// Get the player name // Get the player name
String playerName = arguments.get(0); String playerName = arguments.get(0);
String playerNameLowerCase = playerName.toLowerCase(); String playerNameLowerCase = playerName.toLowerCase();
// Make sure the user is valid // Make sure the user is valid
if (!commandService.getDataSource().isAuthAvailable(playerNameLowerCase)) { if (!dataSource.isAuthAvailable(playerNameLowerCase)) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commandService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }
// Remove the player // Remove the player
if (!commandService.getDataSource().removeAuth(playerNameLowerCase)) { if (!dataSource.removeAuth(playerNameLowerCase)) {
commandService.send(sender, MessageKey.ERROR); commandService.send(sender, MessageKey.ERROR);
return; return;
} }
// Unregister the player // Unregister the player
Player target = commandService.getPlayer(playerNameLowerCase); Player target = bukkitService.getPlayerExact(playerNameLowerCase);
PlayerCache.getInstance().removePlayer(playerNameLowerCase); playerCache.removePlayer(playerNameLowerCase);
Utils.setGroup(target, Utils.GroupType.UNREGISTERED); authGroupHandler.setGroup(target, AuthGroupType.UNREGISTERED);
if (target != null && target.isOnline()) { if (target != null && target.isOnline()) {
if (commandService.getProperty(RegistrationSettings.FORCE)) { if (commandService.getProperty(RegistrationSettings.FORCE)) {
applyUnregisteredEffectsAndTasks(target, commandService); applyUnregisteredEffectsAndTasks(target);
} }
commandService.send(target, MessageKey.UNREGISTERED_SUCCESS); commandService.send(target, MessageKey.UNREGISTERED_SUCCESS);
} }
@ -68,27 +91,18 @@ public class UnregisterAdminCommand implements ExecutableCommand {
* timeout kick, blindness. * timeout kick, blindness.
* *
* @param target the player that was unregistered * @param target the player that was unregistered
* @param service the command service
*/ */
private void applyUnregisteredEffectsAndTasks(Player target, CommandService service) { private void applyUnregisteredEffectsAndTasks(Player target) {
final AuthMe plugin = service.getAuthMe(); // TODO #765: Remove use of Utils method and behave according to settings
final BukkitService bukkitService = service.getBukkitService();
final String playerNameLowerCase = target.getName().toLowerCase();
Utils.teleportToSpawn(target); Utils.teleportToSpawn(target);
LimboCache.getInstance().addLimboPlayer(target);
int timeOut = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
int interval = service.getProperty(RegistrationSettings.MESSAGE_INTERVAL);
if (timeOut != 0) {
BukkitTask id = bukkitService.runTaskLater(new TimeoutTask(plugin, playerNameLowerCase, target), timeOut);
LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setTimeoutTask(id);
}
LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTask(
bukkitService.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(),
playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval)));
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { limboCache.addLimboPlayer(target);
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); limboPlayerTaskManager.registerTimeoutTask(target);
limboPlayerTaskManager.registerMessageTask(target.getName(), false);
final int timeout = commandService.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
if (commandService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
} }
} }
} }

View File

@ -3,10 +3,12 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -14,15 +16,21 @@ import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER;
public class VersionCommand implements ExecutableCommand { public class VersionCommand implements ExecutableCommand {
@Inject
private BukkitService bukkitService;
@Inject
private CommandService commandService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Show some version info // Show some version info
sender.sendMessage(ChatColor.GOLD + "==========[ " + commandService.getProperty(HELP_HEADER) sender.sendMessage(ChatColor.GOLD + "==========[ " + commandService.getProperty(HELP_HEADER)
+ " ABOUT ]=========="); + " ABOUT ]==========");
sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName() sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName()
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")"); + " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
sender.sendMessage(ChatColor.GOLD + "Developers:"); sender.sendMessage(ChatColor.GOLD + "Developers:");
Collection<? extends Player> onlinePlayers = commandService.getOnlinePlayers(); Collection<? extends Player> onlinePlayers = bukkitService.getOnlinePlayers();
printDeveloper(sender, "Xephi", "xephi59", "Lead Developer", onlinePlayers); printDeveloper(sender, "Xephi", "xephi59", "Lead Developer", onlinePlayers);
printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers); printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers);
printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers); printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers);

View File

@ -1,55 +1,47 @@
package fr.xephi.authme.command.executable.captcha; package fr.xephi.authme.command.executable.captcha;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.CaptchaManager;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class CaptchaCommand extends PlayerCommand { public class CaptchaCommand extends PlayerCommand {
@Inject
private PlayerCache playerCache;
@Inject
private CaptchaManager captchaManager;
@Inject
private CommandService commandService;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
final String playerNameLowerCase = player.getName().toLowerCase(); final String playerName = player.getName().toLowerCase();
final String captcha = arguments.get(0);
final AuthMe plugin = commandService.getAuthMe();
PlayerCache playerCache = PlayerCache.getInstance();
// Command logic if (playerCache.isAuthenticated(playerName)) {
if (playerCache.isAuthenticated(playerNameLowerCase)) {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return; } else if (!captchaManager.isCaptchaRequired(playerName)) {
}
if (!commandService.getProperty(SecuritySettings.USE_CAPTCHA)) {
commandService.send(player, MessageKey.USAGE_LOGIN); commandService.send(player, MessageKey.USAGE_LOGIN);
return; } else {
checkCaptcha(player, arguments.get(0));
} }
}
if (!plugin.cap.containsKey(playerNameLowerCase)) { private void checkCaptcha(Player player, String captchaCode) {
commandService.send(player, MessageKey.USAGE_LOGIN); final boolean isCorrectCode = captchaManager.checkCode(player.getName(), captchaCode);
return; if (isCorrectCode) {
commandService.send(player, MessageKey.CAPTCHA_SUCCESS);
commandService.send(player, MessageKey.LOGIN_MESSAGE);
} else {
String newCode = captchaManager.generateCode(player.getName());
commandService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
} }
if (!captcha.equals(plugin.cap.get(playerNameLowerCase))) {
plugin.cap.remove(playerNameLowerCase);
int captchaLength = commandService.getProperty(SecuritySettings.CAPTCHA_LENGTH);
String randStr = RandomString.generate(captchaLength);
plugin.cap.put(playerNameLowerCase, randStr);
commandService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, plugin.cap.get(playerNameLowerCase));
return;
}
plugin.captcha.remove(playerNameLowerCase);
plugin.cap.remove(playerNameLowerCase);
// Show a status message
commandService.send(player, MessageKey.CAPTCHA_SUCCESS);
commandService.send(player, MessageKey.LOGIN_MESSAGE);
} }
} }

View File

@ -1,13 +1,15 @@
package fr.xephi.authme.command.executable.changepassword; package fr.xephi.authme.command.executable.changepassword;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.task.ChangePasswordTask; import fr.xephi.authme.process.Management;
import fr.xephi.authme.util.ValidationService;
import fr.xephi.authme.util.ValidationService.ValidationResult;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -15,27 +17,37 @@ import java.util.List;
*/ */
public class ChangePasswordCommand extends PlayerCommand { public class ChangePasswordCommand extends PlayerCommand {
@Inject
private CommandService commandService;
@Inject
private PlayerCache playerCache;
@Inject
private ValidationService validationService;
@Inject
private Management management;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
String oldPassword = arguments.get(0); String oldPassword = arguments.get(0);
String newPassword = arguments.get(1); String newPassword = arguments.get(1);
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
final PlayerCache playerCache = commandService.getPlayerCache();
if (!playerCache.isAuthenticated(name)) { if (!playerCache.isAuthenticated(name)) {
commandService.send(player, MessageKey.NOT_LOGGED_IN); commandService.send(player, MessageKey.NOT_LOGGED_IN);
return; return;
} }
// Make sure the password is allowed // Make sure the password is allowed
MessageKey passwordError = commandService.validatePassword(newPassword, name); ValidationResult passwordValidation = validationService.validatePassword(newPassword, name);
if (passwordError != null) { if (passwordValidation.hasError()) {
commandService.send(player, passwordError); commandService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return; return;
} }
AuthMe plugin = AuthMe.getInstance();
// TODO ljacqu 20160117: Call async task via Management // TODO ljacqu 20160117: Call async task via Management
commandService.runTaskAsynchronously(new ChangePasswordTask(plugin, player, oldPassword, newPassword)); management.performPasswordChange(player, oldPassword, newPassword);
} }
} }

View File

@ -3,8 +3,10 @@ package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.process.Management;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -12,14 +14,20 @@ import java.util.List;
*/ */
public class AddEmailCommand extends PlayerCommand { public class AddEmailCommand extends PlayerCommand {
@Inject
private Management management;
@Inject
private CommandService commandService;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
String email = arguments.get(0); String email = arguments.get(0);
String emailConfirmation = arguments.get(1); String emailConfirmation = arguments.get(1);
if (email.equals(emailConfirmation)) { if (email.equals(emailConfirmation)) {
// Closer inspection of the mail address handled by the async task // Closer inspection of the mail address handled by the async task
commandService.getManagement().performAddEmail(player, email); management.performAddEmail(player, email);
} else { } else {
commandService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE); commandService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE);
} }

View File

@ -1,9 +1,10 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.process.Management;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -11,11 +12,14 @@ import java.util.List;
*/ */
public class ChangeEmailCommand extends PlayerCommand { public class ChangeEmailCommand extends PlayerCommand {
@Inject
private Management management;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
String playerMailOld = arguments.get(0); String playerMailOld = arguments.get(0);
String playerMailNew = arguments.get(1); String playerMailNew = arguments.get(1);
commandService.getManagement().performChangeEmail(player, playerMailOld, playerMailNew); management.performChangeEmail(player, playerMailOld, playerMailNew);
} }
} }

View File

@ -1,11 +1,12 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandMapper;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -14,9 +15,15 @@ import java.util.List;
*/ */
public class EmailBaseCommand implements ExecutableCommand { public class EmailBaseCommand implements ExecutableCommand {
@Inject
private CommandMapper commandMapper;
@Inject
private HelpProvider helpProvider;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments) {
FoundCommandResult result = commandService.mapPartsToCommand(sender, Collections.singletonList("email")); FoundCommandResult result = commandMapper.mapPartsToCommand(sender, Collections.singletonList("email"));
commandService.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN); helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN);
} }
} }

View File

@ -8,28 +8,44 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class RecoverEmailCommand extends PlayerCommand { public class RecoverEmailCommand extends PlayerCommand {
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private CommandService commandService;
@Inject
private DataSource dataSource;
@Inject
private PlayerCache playerCache;
@Inject
// TODO #655: Remove injected AuthMe instance once Authme#mail is encapsulated
private AuthMe plugin;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
final String playerMail = arguments.get(0); final String playerMail = arguments.get(0);
final String playerName = player.getName(); final String playerName = player.getName();
final AuthMe plugin = commandService.getAuthMe();
if (plugin.mail == null) { if (plugin.mail == null) {
ConsoleLogger.showError("Mail API is not set"); ConsoleLogger.showError("Mail API is not set");
commandService.send(player, MessageKey.ERROR); commandService.send(player, MessageKey.ERROR);
return; return;
} }
DataSource dataSource = commandService.getDataSource();
if (dataSource.isAuthAvailable(playerName)) { if (dataSource.isAuthAvailable(playerName)) {
if (PlayerCache.getInstance().isAuthenticated(playerName)) { if (PlayerCache.getInstance().isAuthenticated(playerName)) {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
@ -37,10 +53,10 @@ public class RecoverEmailCommand extends PlayerCommand {
} }
String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)); String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
HashedPassword hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
PlayerAuth auth; PlayerAuth auth;
if (PlayerCache.getInstance().isAuthenticated(playerName)) { if (playerCache.isAuthenticated(playerName)) {
auth = PlayerCache.getInstance().getAuth(playerName); auth = playerCache.getAuth(playerName);
} else if (dataSource.isAuthAvailable(playerName)) { } else if (dataSource.isAuthAvailable(playerName)) {
auth = dataSource.getAuth(playerName); auth = dataSource.getAuth(playerName);
} else { } else {

View File

@ -1,9 +1,10 @@
package fr.xephi.authme.command.executable.login; package fr.xephi.authme.command.executable.login;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.process.Management;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -11,9 +12,12 @@ import java.util.List;
*/ */
public class LoginCommand extends PlayerCommand { public class LoginCommand extends PlayerCommand {
@Inject
private Management management;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
final String password = arguments.get(0); final String password = arguments.get(0);
commandService.getManagement().performLogin(player, password, false); management.performLogin(player, password, false);
} }
} }

View File

@ -1,9 +1,10 @@
package fr.xephi.authme.command.executable.logout; package fr.xephi.authme.command.executable.logout;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.process.Management;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
/** /**
@ -11,8 +12,11 @@ import java.util.List;
*/ */
public class LogoutCommand extends PlayerCommand { public class LogoutCommand extends PlayerCommand {
@Inject
private Management management;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
commandService.getManagement().performLogout(player); management.performLogout(player);
} }
} }

View File

@ -4,12 +4,14 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH; import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
@ -19,25 +21,31 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PAS
public class RegisterCommand extends PlayerCommand { public class RegisterCommand extends PlayerCommand {
@Inject
private Management management;
@Inject
private CommandService commandService;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) { if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
//for two factor auth we don't need to check the usage //for two factor auth we don't need to check the usage
commandService.getManagement().performRegister(player, "", ""); management.performRegister(player, "", "", true);
return; return;
} }
// Ensure that there is 1 argument, or 2 if confirmation is required // Ensure that there is 1 argument, or 2 if confirmation is required
final boolean useConfirmation = isConfirmationRequired(commandService); final boolean useConfirmation = isConfirmationRequired();
if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) { if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) {
commandService.send(player, MessageKey.USAGE_REGISTER); commandService.send(player, MessageKey.USAGE_REGISTER);
return; return;
} }
if (commandService.getProperty(USE_EMAIL_REGISTRATION)) { if (commandService.getProperty(USE_EMAIL_REGISTRATION)) {
handleEmailRegistration(player, arguments, commandService); handleEmailRegistration(player, arguments);
} else { } else {
handlePasswordRegistration(player, arguments, commandService); handlePasswordRegistration(player, arguments);
} }
} }
@ -46,15 +54,15 @@ public class RegisterCommand extends PlayerCommand {
return "/authme register <playername> <password>"; return "/authme register <playername> <password>";
} }
private void handlePasswordRegistration(Player player, List<String> arguments, CommandService commandService) { private void handlePasswordRegistration(Player player, List<String> arguments) {
if (commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) { if (commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) {
commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR); commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
} else { } else {
commandService.getManagement().performRegister(player, arguments.get(0), ""); management.performRegister(player, arguments.get(0), "", true);
} }
} }
private void handleEmailRegistration(Player player, List<String> arguments, CommandService commandService) { private void handleEmailRegistration(Player player, List<String> arguments) {
if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
player.sendMessage("Cannot register: no email address is set for the server. " player.sendMessage("Cannot register: no email address is set for the server. "
+ "Please contact an administrator"); + "Please contact an administrator");
@ -70,17 +78,16 @@ public class RegisterCommand extends PlayerCommand {
commandService.send(player, MessageKey.USAGE_REGISTER); commandService.send(player, MessageKey.USAGE_REGISTER);
} else { } else {
String thePass = RandomString.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH)); String thePass = RandomString.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH));
commandService.getManagement().performRegister(player, thePass, email); management.performRegister(player, thePass, email, true);
} }
} }
/** /**
* Return whether the password or email has to be confirmed. * Return whether the password or email has to be confirmed.
* *
* @param commandService The command service
* @return True if the confirmation is needed, false otherwise * @return True if the confirmation is needed, false otherwise
*/ */
private boolean isConfirmationRequired(CommandService commandService) { private boolean isConfirmationRequired() {
return commandService.getProperty(USE_EMAIL_REGISTRATION) return commandService.getProperty(USE_EMAIL_REGISTRATION)
? commandService.getProperty(ENABLE_CONFIRM_EMAIL) ? commandService.getProperty(ENABLE_CONFIRM_EMAIL)
: commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION); : commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION);

View File

@ -4,24 +4,35 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.process.Management;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List; import java.util.List;
public class UnregisterCommand extends PlayerCommand { public class UnregisterCommand extends PlayerCommand {
@Inject
private Management management;
@Inject
private CommandService commandService;
@Inject
private PlayerCache playerCache;
@Override @Override
public void runCommand(Player player, List<String> arguments, CommandService commandService) { public void runCommand(Player player, List<String> arguments) {
String playerPass = arguments.get(0); String playerPass = arguments.get(0);
final String playerNameLowerCase = player.getName().toLowerCase(); final String playerNameLowerCase = player.getName().toLowerCase();
// Make sure the player is authenticated // Make sure the player is authenticated
if (!PlayerCache.getInstance().isAuthenticated(playerNameLowerCase)) { if (!playerCache.isAuthenticated(playerNameLowerCase)) {
commandService.send(player, MessageKey.NOT_LOGGED_IN); commandService.send(player, MessageKey.NOT_LOGGED_IN);
return; return;
} }
// Unregister the player // Unregister the player
commandService.getManagement().performUnregister(player, playerPass, false); management.performUnregister(player, playerPass, false);
} }
} }

View File

@ -4,16 +4,18 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import fr.xephi.authme.command.CommandArgumentDescription; import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandPermissions;
import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.permission.DefaultPermission; import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.PluginSettings;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -23,7 +25,7 @@ import static java.util.Collections.singletonList;
/** /**
* Help syntax generator for AuthMe commands. * Help syntax generator for AuthMe commands.
*/ */
public class HelpProvider { public class HelpProvider implements SettingsDependent {
// --- Bit flags --- // --- Bit flags ---
/** Set to <i>not</i> show the command. */ /** Set to <i>not</i> show the command. */
@ -43,14 +45,15 @@ public class HelpProvider {
public static final int ALL_OPTIONS = ~HIDE_COMMAND; public static final int ALL_OPTIONS = ~HIDE_COMMAND;
private final PermissionsManager permissionsManager; private final PermissionsManager permissionsManager;
private final String helpHeader; private String helpHeader;
public HelpProvider(PermissionsManager permissionsManager, String helpHeader) { @Inject
HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
this.permissionsManager = permissionsManager; this.permissionsManager = permissionsManager;
this.helpHeader = helpHeader; loadSettings(settings);
} }
public List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) { private List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
if (result.getCommandDescription() == null) { if (result.getCommandDescription() == null) {
return singletonList(ChatColor.DARK_RED + "Failed to retrieve any help information!"); return singletonList(ChatColor.DARK_RED + "Failed to retrieve any help information!");
} }
@ -84,6 +87,25 @@ public class HelpProvider {
return lines; return lines;
} }
/**
* Output the help for a given command.
*
* @param sender The sender to output the help to
* @param result The result to output information about
* @param options Output options, see {@link HelpProvider}
*/
public void outputHelp(CommandSender sender, FoundCommandResult result, int options) {
List<String> lines = printHelp(sender, result, options);
for (String line : lines) {
sender.sendMessage(line);
}
}
@Override
public void loadSettings(NewSetting settings) {
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
}
private static void printDetailedDescription(CommandDescription command, List<String> lines) { private static void printDetailedDescription(CommandDescription command, List<String> lines) {
lines.add(ChatColor.GOLD + "Short description: " + ChatColor.WHITE + command.getDescription()); lines.add(ChatColor.GOLD + "Short description: " + ChatColor.WHITE + command.getDescription());
lines.add(ChatColor.GOLD + "Detailed description:"); lines.add(ChatColor.GOLD + "Detailed description:");
@ -110,7 +132,6 @@ public class HelpProvider {
} }
private static void printAlternatives(CommandDescription command, List<String> correctLabels, List<String> lines) { private static void printAlternatives(CommandDescription command, List<String> correctLabels, List<String> lines) {
// TODO ljacqu 20151219: Need to show alternatives for base labels too? E.g. /r for /register
if (command.getLabels().size() <= 1 || correctLabels.size() <= 1) { if (command.getLabels().size() <= 1 || correctLabels.size() <= 1) {
return; return;
} }
@ -130,25 +151,22 @@ public class HelpProvider {
private static void printPermissions(CommandDescription command, CommandSender sender, private static void printPermissions(CommandDescription command, CommandSender sender,
PermissionsManager permissionsManager, List<String> lines) { PermissionsManager permissionsManager, List<String> lines) {
CommandPermissions permissions = command.getCommandPermissions(); PermissionNode permission = command.getPermission();
// TODO ljacqu 20151224: Isn't it possible to have a default permission but no permission nodes? if (permission == null) {
if (permissions == null || CollectionUtils.isEmpty(permissions.getPermissionNodes())) {
return; return;
} }
lines.add(ChatColor.GOLD + "Permissions:"); lines.add(ChatColor.GOLD + "Permissions:");
for (PermissionNode node : permissions.getPermissionNodes()) { boolean hasPermission = permissionsManager.hasPermission(sender, permission);
boolean hasPermission = permissionsManager.hasPermission(sender, node); final String nodePermsString = "" + ChatColor.GRAY + ChatColor.ITALIC
final String nodePermsString = "" + ChatColor.GRAY + ChatColor.ITALIC + (hasPermission ? " (You have permission)" : " (No permission)");
+ (hasPermission ? " (You have permission)" : " (No permission)"); lines.add(" " + ChatColor.YELLOW + ChatColor.ITALIC + permission.getNode() + nodePermsString);
lines.add(" " + ChatColor.YELLOW + ChatColor.ITALIC + node.getNode() + nodePermsString);
}
// Addendum to the line to specify whether the sender has permission or not when default is OP_ONLY // Addendum to the line to specify whether the sender has permission or not when default is OP_ONLY
final DefaultPermission defaultPermission = permissions.getDefaultPermission(); final DefaultPermission defaultPermission = permission.getDefaultPermission();
String addendum = ""; String addendum = "";
if (DefaultPermission.OP_ONLY.equals(defaultPermission)) { if (DefaultPermission.OP_ONLY.equals(defaultPermission)) {
addendum = PermissionsManager.evaluateDefaultPermission(defaultPermission, sender) addendum = defaultPermission.evaluate(sender)
? " (You have permission)" ? " (You have permission)"
: " (No permission)"; : " (No permission)";
} }
@ -156,7 +174,7 @@ public class HelpProvider {
+ defaultPermission.getTitle() + addendum); + defaultPermission.getTitle() + addendum);
// Evaluate if the sender has permission to the command // Evaluate if the sender has permission to the command
if (permissionsManager.hasPermission(sender, command)) { if (permissionsManager.hasPermission(sender, command.getPermission())) {
lines.add(ChatColor.GOLD + " Result: " + ChatColor.GREEN + ChatColor.ITALIC + "You have permission"); lines.add(ChatColor.GOLD + " Result: " + ChatColor.GREEN + ChatColor.ITALIC + "You have permission");
} else { } else {
lines.add(ChatColor.GOLD + " Result: " + ChatColor.DARK_RED + ChatColor.ITALIC + "No permission"); lines.add(ChatColor.GOLD + " Result: " + ChatColor.DARK_RED + ChatColor.ITALIC + "No permission");

View File

@ -1,7 +1,16 @@
package fr.xephi.authme.converter; package fr.xephi.authme.converter;
import org.bukkit.command.CommandSender;
/** /**
* Common supertype for AuthMe converters. * Interface for AuthMe converters.
*/ */
public interface Converter extends Runnable { public interface Converter {
/**
* Execute the conversion.
*
* @param sender the sender who initialized the conversion
*/
void execute(CommandSender sender);
} }

View File

@ -1,47 +1,46 @@
package fr.xephi.authme.converter; package fr.xephi.authme.converter;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.ConverterSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
/** /**
* @author Xephi59 * Converter for CrazyLogin to AuthMe.
*/ */
public class CrazyLoginConverter implements Converter { public class CrazyLoginConverter implements Converter {
private final DataSource database; private final DataSource database;
private final CommandSender sender; private final NewSetting settings;
private final File dataFolder;
/** @Inject
* Constructor for CrazyLoginConverter. CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings) {
* this.dataFolder = dataFolder;
* @param instance AuthMe this.database = dataSource;
* @param sender CommandSender this.settings = settings;
*/
public CrazyLoginConverter(AuthMe instance, CommandSender sender) {
this.database = instance.getDataSource();
this.sender = sender;
} }
@Override @Override
public void run() { public void execute(CommandSender sender) {
String fileName = Settings.crazyloginFileName; String fileName = settings.getProperty(ConverterSettings.CRAZYLOGIN_FILE_NAME);
try { File source = new File(dataFolder, fileName);
File source = new File(AuthMe.getInstance().getDataFolder() + File.separator + fileName); if (!source.exists()) {
if (!source.exists()) { sender.sendMessage("CrazyLogin file not found, please put " + fileName + " in AuthMe folder!");
sender.sendMessage("Error while trying to import data, please put " + fileName + " in AuthMe folder!"); return;
return; }
}
String line; String line;
BufferedReader users = new BufferedReader(new FileReader(source)); try (BufferedReader users = new BufferedReader(new FileReader(source))) {
while ((line = users.readLine()) != null) { while ((line = users.readLine()) != null) {
if (line.contains("|")) { if (line.contains("|")) {
String[] args = line.split("\\|"); String[] args = line.split("\\|");
@ -49,22 +48,21 @@ public class CrazyLoginConverter implements Converter {
continue; continue;
} }
String playerName = args[0]; String playerName = args[0];
String psw = args[1]; String password = args[1];
if (psw != null) { if (password != null) {
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(playerName.toLowerCase()) .name(playerName.toLowerCase())
.realName(playerName) .realName(playerName)
.password(psw, null) .password(password, null)
.build(); .build();
database.saveAuth(auth); database.saveAuth(auth);
} }
} }
} }
users.close();
ConsoleLogger.info("CrazyLogin database has been imported correctly"); ConsoleLogger.info("CrazyLogin database has been imported correctly");
} catch (IOException ex) { } catch (IOException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.showError("Can't open the crazylogin database file! Does it exist?"); ConsoleLogger.showError("Can't open the crazylogin database file! Does it exist?");
ConsoleLogger.logException("Encountered", ex);
} }
} }

View File

@ -12,7 +12,7 @@ import java.util.List;
/** /**
* Mandatory migration from the deprecated flat file datasource to SQLite. * Mandatory migration from the deprecated flat file datasource to SQLite.
*/ */
public class ForceFlatToSqlite implements Converter { public class ForceFlatToSqlite {
private final DataSource source; private final DataSource source;
private final DataSource destination; private final DataSource destination;
@ -31,7 +31,6 @@ public class ForceFlatToSqlite implements Converter {
/** /**
* Perform the conversion. * Perform the conversion.
*/ */
@Override
public void run() { public void run() {
List<String> skippedPlayers = new ArrayList<>(); List<String> skippedPlayers = new ArrayList<>();
for (PlayerAuth auth : source.getAllAuths()) { for (PlayerAuth auth : source.getAllAuths()) {

View File

@ -1,14 +1,16 @@
package fr.xephi.authme.converter; package fr.xephi.authme.converter;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.ConverterSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@ -21,24 +23,26 @@ import java.util.Map.Entry;
*/ */
public class RakamakConverter implements Converter { public class RakamakConverter implements Converter {
private final AuthMe instance;
private final DataSource database; private final DataSource database;
private final CommandSender sender; private final NewSetting settings;
private final File pluginFolder; private final File pluginFolder;
private final PasswordSecurity passwordSecurity;
public RakamakConverter(AuthMe instance, CommandSender sender) { @Inject
this.instance = instance; RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings,
this.database = instance.getDataSource(); PasswordSecurity passwordSecurity) {
this.sender = sender; this.database = dataSource;
pluginFolder = instance.getDataFolder(); this.settings = settings;
this.pluginFolder = dataFolder;
this.passwordSecurity = passwordSecurity;
} }
@Override @Override
// TODO ljacqu 20151229: Restructure this into smaller portions // TODO ljacqu 20151229: Restructure this into smaller portions
public void run() { public void execute(CommandSender sender) {
boolean useIP = Settings.rakamakUseIp; boolean useIP = settings.getProperty(ConverterSettings.RAKAMAK_USE_IP);
String fileName = Settings.rakamakUsers; String fileName = settings.getProperty(ConverterSettings.RAKAMAK_FILE_NAME);
String ipFileName = Settings.rakamakUsersIp; String ipFileName = settings.getProperty(ConverterSettings.RAKAMAK_IP_FILE_NAME);
File source = new File(pluginFolder, fileName); File source = new File(pluginFolder, fileName);
File ipfiles = new File(pluginFolder, ipFileName); File ipfiles = new File(pluginFolder, ipFileName);
HashMap<String, String> playerIP = new HashMap<>(); HashMap<String, String> playerIP = new HashMap<>();
@ -60,7 +64,6 @@ public class RakamakConverter implements Converter {
ipFile.close(); ipFile.close();
users = new BufferedReader(new FileReader(source)); users = new BufferedReader(new FileReader(source));
PasswordSecurity passwordSecurity = instance.getPasswordSecurity();
while ((line = users.readLine()) != null) { while ((line = users.readLine()) != null) {
if (line.contains("=")) { if (line.contains("=")) {
String[] arguments = line.split("="); String[] arguments = line.split("=");

View File

@ -5,9 +5,11 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import javax.inject.Inject;
import java.io.File; import java.io.File;
import static fr.xephi.authme.util.StringUtils.makePath; import static fr.xephi.authme.util.StringUtils.makePath;
@ -19,13 +21,14 @@ public class RoyalAuthConverter implements Converter {
private final AuthMe plugin; private final AuthMe plugin;
private final DataSource dataSource; private final DataSource dataSource;
public RoyalAuthConverter(AuthMe plugin) { @Inject
RoyalAuthConverter(AuthMe plugin, DataSource dataSource) {
this.plugin = plugin; this.plugin = plugin;
this.dataSource = plugin.getDataSource(); this.dataSource = dataSource;
} }
@Override @Override
public void run() { public void execute(CommandSender sender) {
for (OfflinePlayer player : plugin.getServer().getOfflinePlayers()) { for (OfflinePlayer player : plugin.getServer().getOfflinePlayers()) {
try { try {
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();

View File

@ -1,40 +1,43 @@
package fr.xephi.authme.converter; package fr.xephi.authme.converter;
import fr.xephi.authme.settings.NewSetting;
import org.bukkit.command.CommandSender;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSourceType; import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.datasource.SQLite; import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.NewSetting;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
public class SqliteToSql implements Converter { public class SqliteToSql implements Converter {
private final AuthMe plugin;
private final CommandSender sender;
private final NewSetting settings; private final NewSetting settings;
private final DataSource dataSource;
private final Messages messages;
public SqliteToSql(AuthMe plugin, CommandSender sender, NewSetting settings) { @Inject
this.plugin = plugin; SqliteToSql(NewSetting settings, DataSource dataSource, Messages messages) {
this.sender = sender;
this.settings = settings; this.settings = settings;
this.dataSource = dataSource;
this.messages = messages;
} }
@Override @Override
public void run() { public void execute(CommandSender sender) {
if (plugin.getDataSource().getType() != DataSourceType.MYSQL) { if (dataSource.getType() != DataSourceType.MYSQL) {
sender.sendMessage("Please configure your mySQL connection and re-run this command"); sender.sendMessage("Please configure your mySQL connection and re-run this command");
return; return;
} }
try { try {
SQLite data = new SQLite(settings); SQLite data = new SQLite(settings);
for (PlayerAuth auth : data.getAllAuths()) { for (PlayerAuth auth : data.getAllAuths()) {
plugin.getDataSource().saveAuth(auth); dataSource.saveAuth(auth);
} }
} catch (Exception e) { } catch (Exception e) {
plugin.getMessages().send(sender, MessageKey.ERROR); messages.send(sender, MessageKey.ERROR);
ConsoleLogger.logException("Problem during SQLite to SQL conversion:", e); ConsoleLogger.logException("Problem during SQLite to SQL conversion:", e);
} }
} }

View File

@ -4,18 +4,19 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
public class vAuthConverter implements Converter { public class vAuthConverter implements Converter {
private final AuthMe plugin; private final AuthMe plugin;
private final CommandSender sender;
public vAuthConverter(AuthMe plugin, CommandSender sender) { @Inject
vAuthConverter(AuthMe plugin) {
this.plugin = plugin; this.plugin = plugin;
this.sender = sender;
} }
@Override @Override
public void run() { public void execute(CommandSender sender) {
try { try {
new vAuthFileReader(plugin).convert(); new vAuthFileReader(plugin).convert();
} catch (Exception e) { } catch (Exception e) {

View File

@ -3,18 +3,19 @@ package fr.xephi.authme.converter;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject;
public class xAuthConverter implements Converter { public class xAuthConverter implements Converter {
private final AuthMe plugin; private final AuthMe plugin;
private final CommandSender sender;
public xAuthConverter(AuthMe plugin, CommandSender sender) { @Inject
xAuthConverter(AuthMe plugin) {
this.plugin = plugin; this.plugin = plugin;
this.sender = sender;
} }
@Override @Override
public void run() { public void execute(CommandSender sender) {
try { try {
Class.forName("de.luricos.bukkit.xAuth.xAuth"); Class.forName("de.luricos.bukkit.xAuth.xAuth");
xAuthToFlat converter = new xAuthToFlat(plugin, sender); xAuthToFlat converter = new xAuthToFlat(plugin, sender);

View File

@ -8,6 +8,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
@ -15,12 +16,11 @@ import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/**
*/
public class CacheDataSource implements DataSource { public class CacheDataSource implements DataSource {
private final DataSource source; private final DataSource source;
@ -41,7 +41,8 @@ public class CacheDataSource implements DataSource {
.build()) .build())
); );
cachedAuths = CacheBuilder.newBuilder() cachedAuths = CacheBuilder.newBuilder()
.refreshAfterWrite(8, TimeUnit.MINUTES) .refreshAfterWrite(5, TimeUnit.MINUTES)
.expireAfterAccess(15, TimeUnit.MINUTES)
.build(new CacheLoader<String, Optional<PlayerAuth>>() { .build(new CacheLoader<String, Optional<PlayerAuth>>() {
@Override @Override
public Optional<PlayerAuth> load(String key) { public Optional<PlayerAuth> load(String key) {
@ -53,6 +54,7 @@ public class CacheDataSource implements DataSource {
return executorService.submit(new Callable<Optional<PlayerAuth>>() { return executorService.submit(new Callable<Optional<PlayerAuth>>() {
@Override @Override
public Optional<PlayerAuth> call() { public Optional<PlayerAuth> call() {
ConsoleLogger.debug("REFRESH " + key);
return load(key); return load(key);
} }
}); });
@ -70,7 +72,7 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized boolean isAuthAvailable(String user) { public boolean isAuthAvailable(String user) {
return getAuth(user) != null; return getAuth(user) != null;
} }
@ -85,13 +87,13 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized PlayerAuth getAuth(String user) { public PlayerAuth getAuth(String user) {
user = user.toLowerCase(); user = user.toLowerCase();
return cachedAuths.getUnchecked(user).orNull(); return cachedAuths.getUnchecked(user).orNull();
} }
@Override @Override
public synchronized boolean saveAuth(PlayerAuth auth) { public boolean saveAuth(PlayerAuth auth) {
boolean result = source.saveAuth(auth); boolean result = source.saveAuth(auth);
if (result) { if (result) {
cachedAuths.refresh(auth.getNickname()); cachedAuths.refresh(auth.getNickname());
@ -100,7 +102,7 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized boolean updatePassword(PlayerAuth auth) { public boolean updatePassword(PlayerAuth auth) {
boolean result = source.updatePassword(auth); boolean result = source.updatePassword(auth);
if (result) { if (result) {
cachedAuths.refresh(auth.getNickname()); cachedAuths.refresh(auth.getNickname());
@ -137,16 +139,17 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public List<String> autoPurgeDatabase(long until) { public Set<String> autoPurgeDatabase(long until) {
List<String> cleared = source.autoPurgeDatabase(until); Set<String> cleared = source.autoPurgeDatabase(until);
for (String name : cleared) { for (String name : cleared) {
cachedAuths.invalidate(name); cachedAuths.invalidate(name);
} }
return cleared; return cleared;
} }
@Override @Override
public synchronized boolean removeAuth(String name) { public boolean removeAuth(String name) {
name = name.toLowerCase(); name = name.toLowerCase();
boolean result = source.removeAuth(name); boolean result = source.removeAuth(name);
if (result) { if (result) {
@ -156,7 +159,7 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized void close() { public void close() {
source.close(); source.close();
cachedAuths.invalidateAll(); cachedAuths.invalidateAll();
executorService.shutdown(); executorService.shutdown();
@ -168,7 +171,7 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized boolean updateEmail(final PlayerAuth auth) { public boolean updateEmail(final PlayerAuth auth) {
boolean result = source.updateEmail(auth); boolean result = source.updateEmail(auth);
if (result) { if (result) {
cachedAuths.refresh(auth.getNickname()); cachedAuths.refresh(auth.getNickname());
@ -177,17 +180,17 @@ public class CacheDataSource implements DataSource {
} }
@Override @Override
public synchronized List<String> getAllAuthsByIp(final String ip) { public List<String> getAllAuthsByIp(final String ip) {
return source.getAllAuthsByIp(ip); return source.getAllAuthsByIp(ip);
} }
@Override @Override
public synchronized int countAuthsByEmail(final String email) { public int countAuthsByEmail(final String email) {
return source.countAuthsByEmail(email); return source.countAuthsByEmail(email);
} }
@Override @Override
public synchronized void purgeBanned(final List<String> banned) { public void purgeBanned(final Set<String> banned) {
source.purgeBanned(banned); source.purgeBanned(banned);
cachedAuths.invalidateAll(banned); cachedAuths.invalidateAll(banned);
} }

View File

@ -1,14 +1,16 @@
package fr.xephi.authme.datasource; package fr.xephi.authme.datasource;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* Interface for manipulating {@link PlayerAuth} objects from a data source. * Interface for manipulating {@link PlayerAuth} objects from a data source.
*/ */
public interface DataSource { public interface DataSource extends Reloadable {
/** /**
* Return whether there is a record for the given username. * Return whether there is a record for the given username.
@ -74,7 +76,7 @@ public interface DataSource {
* @param until The minimum last login * @param until The minimum last login
* @return The account names that have been removed * @return The account names that have been removed
*/ */
List<String> autoPurgeDatabase(long until); Set<String> autoPurgeDatabase(long until);
/** /**
* Remove a user record from the database. * Remove a user record from the database.
@ -126,7 +128,7 @@ public interface DataSource {
* *
* @param banned the list of players to delete * @param banned the list of players to delete
*/ */
void purgeBanned(List<String> banned); void purgeBanned(Set<String> banned);
/** /**
* Return the data source type. * Return the data source type.
@ -204,6 +206,7 @@ public interface DataSource {
/** /**
* Reload the data source. * Reload the data source.
*/ */
@Override
void reload(); void reload();
} }

View File

@ -17,7 +17,9 @@ import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* Deprecated flat file datasource. The only method guaranteed to work is {@link FlatFile#getAllAuths()} * Deprecated flat file datasource. The only method guaranteed to work is {@link FlatFile#getAllAuths()}
@ -227,11 +229,11 @@ public class FlatFile implements DataSource {
} }
@Override @Override
public List<String> autoPurgeDatabase(long until) { public Set<String> autoPurgeDatabase(long until) {
BufferedReader br = null; BufferedReader br = null;
BufferedWriter bw = null; BufferedWriter bw = null;
ArrayList<String> lines = new ArrayList<>(); ArrayList<String> lines = new ArrayList<>();
List<String> cleared = new ArrayList<>(); Set<String> cleared = new HashSet<>();
try { try {
br = new BufferedReader(new FileReader(source)); br = new BufferedReader(new FileReader(source));
String line; String line;
@ -256,6 +258,7 @@ public class FlatFile implements DataSource {
silentClose(br); silentClose(br);
silentClose(bw); silentClose(bw);
} }
return cleared; return cleared;
} }
@ -414,7 +417,7 @@ public class FlatFile implements DataSource {
} }
@Override @Override
public void purgeBanned(List<String> banned) { public void purgeBanned(Set<String> banned) {
BufferedReader br = null; BufferedReader br = null;
BufferedWriter bw = null; BufferedWriter bw = null;
ArrayList<String> lines = new ArrayList<>(); ArrayList<String> lines = new ArrayList<>();

View File

@ -3,6 +3,7 @@ package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
@ -24,10 +25,10 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/**
*/
public class MySQL implements DataSource { public class MySQL implements DataSource {
private final String host; private final String host;
@ -105,34 +106,36 @@ public class MySQL implements DataSource {
ds = hikariDataSource; ds = hikariDataSource;
} }
private synchronized void setConnectionArguments() throws RuntimeException { private void setConnectionArguments() throws RuntimeException {
ds = new HikariDataSource(); ds = new HikariDataSource();
ds.setPoolName("AuthMeMYSQLPool"); ds.setPoolName("AuthMeMYSQLPool");
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);
ds.addDataSourceProperty("rewriteBatchedStatements", "true");
ds.addDataSourceProperty("jdbcCompliantTruncation", "false");
ds.addDataSourceProperty("cachePrepStmts", "true");
ds.addDataSourceProperty("prepStmtCacheSize", "250");
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
//set utf-8 as default encoding // Database URL
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);
// Auth
ds.setUsername(this.username);
ds.setPassword(this.password);
// Encoding
ds.addDataSourceProperty("characterEncoding", "utf8"); ds.addDataSourceProperty("characterEncoding", "utf8");
ds.addDataSourceProperty("encoding","UTF-8"); ds.addDataSourceProperty("encoding","UTF-8");
ds.addDataSourceProperty("useUnicode", "true"); ds.addDataSourceProperty("useUnicode", "true");
ds.setUsername(this.username); // Random stuff
ds.setPassword(this.password); ds.addDataSourceProperty("rewriteBatchedStatements", "true");
ds.setInitializationFailFast(true); // Don't start the plugin if the database is unavailable ds.addDataSourceProperty("jdbcCompliantTruncation", "false");
ds.setMaxLifetime(180000); // 3 Min
ds.setIdleTimeout(60000); // 1 Min // Caching
ds.setMinimumIdle(2); ds.addDataSourceProperty("cachePrepStmts", "true");
ds.setMaximumPoolSize((Runtime.getRuntime().availableProcessors() * 2) + 1); ds.addDataSourceProperty("prepStmtCacheSize", "250");
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); ConsoleLogger.info("Connection arguments loaded, Hikari ConnectionPool ready!");
} }
@Override @Override
public synchronized void reload() throws RuntimeException { public void reload() throws RuntimeException {
if (ds != null) { if (ds != null) {
ds.close(); ds.close();
} }
@ -140,11 +143,11 @@ public class MySQL implements DataSource {
ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!"); ConsoleLogger.info("Hikari ConnectionPool arguments reloaded!");
} }
private synchronized Connection getConnection() throws SQLException { private Connection getConnection() throws SQLException {
return ds.getConnection(); return ds.getConnection();
} }
private synchronized void setupConnection() throws SQLException { private void setupConnection() throws SQLException {
try (Connection con = getConnection()) { try (Connection con = getConnection()) {
Statement st = con.createStatement(); Statement st = con.createStatement();
DatabaseMetaData md = con.getMetaData(); DatabaseMetaData md = con.getMetaData();
@ -257,7 +260,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean isAuthAvailable(String user) { public boolean isAuthAvailable(String user) {
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
ResultSet rs = null; ResultSet rs = null;
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
@ -293,7 +296,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized PlayerAuth getAuth(String user) { public PlayerAuth getAuth(String user) {
String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;"; String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;";
PlayerAuth auth; PlayerAuth auth;
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
@ -327,7 +330,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean saveAuth(PlayerAuth auth) { public boolean saveAuth(PlayerAuth auth) {
try (Connection con = getConnection()) { try (Connection con = getConnection()) {
PreparedStatement pst; PreparedStatement pst;
PreparedStatement pst2; PreparedStatement pst2;
@ -424,6 +427,7 @@ public class MySQL implements DataSource {
rs.close(); rs.close();
pst.close(); pst.close();
} else if (hashAlgorithm == HashAlgorithm.WORDPRESS) { } else if (hashAlgorithm == HashAlgorithm.WORDPRESS) {
// NOTE: Eclipse says pst should be closed HERE, but it's a bug, we already close it above. -sgdc3
pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"); pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;");
pst.setString(1, auth.getNickname()); pst.setString(1, auth.getNickname());
rs = pst.executeQuery(); rs = pst.executeQuery();
@ -500,6 +504,7 @@ public class MySQL implements DataSource {
rs.close(); rs.close();
pst.close(); pst.close();
} else if (hashAlgorithm == HashAlgorithm.XFBCRYPT) { } else if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
// NOTE: Eclipse says pst should be closed HERE, but it's a bug, we already close it above. -sgdc3
pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"); pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;");
pst.setString(1, auth.getNickname()); pst.setString(1, auth.getNickname());
rs = pst.executeQuery(); rs = pst.executeQuery();
@ -528,7 +533,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean updatePassword(PlayerAuth auth) { public boolean updatePassword(PlayerAuth auth) {
return updatePassword(auth.getNickname(), auth.getPassword()); return updatePassword(auth.getNickname(), auth.getPassword());
} }
@ -591,7 +596,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean updateSession(PlayerAuth auth) { public boolean updateSession(PlayerAuth auth) {
String sql = "UPDATE " + tableName + " SET " String sql = "UPDATE " + tableName + " SET "
+ col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; + col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
@ -608,8 +613,8 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized List<String> autoPurgeDatabase(long until) { public Set<String> autoPurgeDatabase(long until) {
List<String> list = new ArrayList<>(); Set<String> list = new HashSet<>();
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;"; String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;"; String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
try (Connection con = getConnection(); try (Connection con = getConnection();
@ -626,11 +631,12 @@ public class MySQL implements DataSource {
} catch (SQLException ex) { } catch (SQLException ex) {
logSqlException(ex); logSqlException(ex);
} }
return list; return list;
} }
@Override @Override
public synchronized boolean removeAuth(String user) { public boolean removeAuth(String user) {
user = user.toLowerCase(); user = user.toLowerCase();
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
PreparedStatement xfSelect = null; PreparedStatement xfSelect = null;
@ -663,7 +669,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean updateQuitLoc(PlayerAuth auth) { public boolean updateQuitLoc(PlayerAuth auth) {
String sql = "UPDATE " + tableName String sql = "UPDATE " + tableName
+ " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?" + " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?"
+ " WHERE " + col.NAME + "=?;"; + " WHERE " + col.NAME + "=?;";
@ -682,7 +688,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized boolean updateEmail(PlayerAuth auth) { public boolean updateEmail(PlayerAuth auth) {
String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;"; String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getEmail()); pst.setString(1, auth.getEmail());
@ -696,14 +702,14 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized void close() { public void close() {
if (ds != null && !ds.isClosed()) { if (ds != null && !ds.isClosed()) {
ds.close(); ds.close();
} }
} }
@Override @Override
public synchronized List<String> getAllAuthsByIp(String ip) { public List<String> getAllAuthsByIp(String ip) {
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;"; String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
@ -720,7 +726,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized int countAuthsByEmail(String email) { public int countAuthsByEmail(String email) {
String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)"; String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, email); pst.setString(1, email);
@ -736,7 +742,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public synchronized void purgeBanned(List<String> banned) { public void purgeBanned(Set<String> banned) {
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
for (String name : banned) { for (String name : banned) {

View File

@ -1,14 +1,5 @@
package fr.xephi.authme.datasource; package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.StringUtils;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -16,7 +7,19 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.StringUtils;
/** /**
*/ */
@ -61,14 +64,13 @@ public class SQLite implements DataSource {
ConsoleLogger.logException("Error while executing SQL statement:", e); ConsoleLogger.logException("Error while executing SQL statement:", e);
} }
private synchronized void connect() throws ClassNotFoundException, SQLException { private void connect() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.JDBC"); Class.forName("org.sqlite.JDBC");
ConsoleLogger.info("SQLite driver loaded"); ConsoleLogger.info("SQLite driver loaded");
this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db"); this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db");
} }
private synchronized void setup() throws SQLException { private void setup() throws SQLException {
Statement st = null; Statement st = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@ -131,11 +133,17 @@ public class SQLite implements DataSource {
@Override @Override
public void reload() { public void reload() {
// TODO 20160309: Implement reloading close(con);
try {
this.connect();
this.setup();
} catch (ClassNotFoundException | SQLException ex) {
ConsoleLogger.logException("Error during SQLite initialization:", ex);
}
} }
@Override @Override
public synchronized boolean isAuthAvailable(String user) { public boolean isAuthAvailable(String user) {
PreparedStatement pst = null; PreparedStatement pst = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@ -173,7 +181,7 @@ public class SQLite implements DataSource {
} }
@Override @Override
public synchronized PlayerAuth getAuth(String user) { public PlayerAuth getAuth(String user) {
PreparedStatement pst = null; PreparedStatement pst = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@ -193,7 +201,7 @@ public class SQLite implements DataSource {
} }
@Override @Override
public synchronized boolean saveAuth(PlayerAuth auth) { public boolean saveAuth(PlayerAuth auth) {
PreparedStatement pst = null; PreparedStatement pst = null;
try { try {
HashedPassword password = auth.getPassword(); HashedPassword password = auth.getPassword();
@ -234,7 +242,7 @@ public class SQLite implements DataSource {
} }
@Override @Override
public synchronized boolean updatePassword(PlayerAuth auth) { public boolean updatePassword(PlayerAuth auth) {
return updatePassword(auth.getNickname(), auth.getPassword()); return updatePassword(auth.getNickname(), auth.getPassword());
} }
@ -285,8 +293,8 @@ public class SQLite implements DataSource {
} }
@Override @Override
public List<String> autoPurgeDatabase(long until) { public Set<String> autoPurgeDatabase(long until) {
List<String> list = new ArrayList<>(); Set<String> list = new HashSet<>();
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;"; String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;"; String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
try (PreparedStatement selectPst = con.prepareStatement(select); try (PreparedStatement selectPst = con.prepareStatement(select);
@ -302,11 +310,12 @@ public class SQLite implements DataSource {
} catch (SQLException ex) { } catch (SQLException ex) {
logSqlException(ex); logSqlException(ex);
} }
return list; return list;
} }
@Override @Override
public synchronized boolean removeAuth(String user) { public boolean removeAuth(String user) {
PreparedStatement pst = null; PreparedStatement pst = null;
try { try {
pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"); pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;");
@ -356,7 +365,7 @@ public class SQLite implements DataSource {
} }
@Override @Override
public synchronized void close() { public void close() {
try { try {
if (con != null && !con.isClosed()) { if (con != null && !con.isClosed()) {
con.close(); con.close();
@ -376,6 +385,16 @@ public class SQLite implements DataSource {
} }
} }
private void close(Connection con) {
if (con != null) {
try {
con.close();
} catch (SQLException ex) {
logSqlException(ex);
}
}
}
private void close(ResultSet rs) { private void close(ResultSet rs) {
if (rs != null) { if (rs != null) {
try { try {
@ -425,7 +444,7 @@ public class SQLite implements DataSource {
} }
@Override @Override
public void purgeBanned(List<String> banned) { public void purgeBanned(Set<String> banned) {
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) { try (PreparedStatement pst = con.prepareStatement(sql)) {
for (String name : banned) { for (String name : banned) {

View File

@ -19,25 +19,13 @@ public abstract class AbstractTeleportEvent extends CustomEvent implements Cance
* *
* @param isAsync Whether to fire the event asynchronously or not * @param isAsync Whether to fire the event asynchronously or not
* @param player The player * @param player The player
* @param from The location the player is being teleported away from
* @param to The teleport destination
*/
public AbstractTeleportEvent(boolean isAsync, Player player, Location from, Location to) {
super(isAsync);
this.player = player;
this.from = from;
this.to = to;
}
/**
* Constructor, using the player's current location as "from" location.
*
* @param isAsync Whether to fire the event asynchronously or not
* @param player The player
* @param to The teleport destination * @param to The teleport destination
*/ */
public AbstractTeleportEvent(boolean isAsync, Player player, Location to) { public AbstractTeleportEvent(boolean isAsync, Player player, Location to) {
this(isAsync, player, player.getLocation(), to); super(isAsync);
this.player = player;
this.from = player.getLocation();
this.to = to;
} }
/** /**

View File

@ -5,7 +5,8 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* This event is called when a player uses the /login command with correct credentials. * This event is called when a player uses the login command,
* it's fired even when a user does a /login with invalid password.
* {@link #setCanLogin(boolean) event.setCanLogin(false)} prevents the player from logging in. * {@link #setCanLogin(boolean) event.setCanLogin(false)} prevents the player from logging in.
*/ */
public class AuthMeAsyncPreLoginEvent extends CustomEvent { public class AuthMeAsyncPreLoginEvent extends CustomEvent {

View File

@ -17,11 +17,10 @@ public class FirstSpawnTeleportEvent extends AbstractTeleportEvent {
* Constructor. * Constructor.
* *
* @param player The player * @param player The player
* @param from The location the player is being teleported away from
* @param to The teleport destination * @param to The teleport destination
*/ */
public FirstSpawnTeleportEvent(Player player, Location from, Location to) { public FirstSpawnTeleportEvent(Player player, Location to) {
super(true, player, from, to); super(false, player, to);
} }
/** /**

View File

@ -30,6 +30,17 @@ public class LoginEvent extends CustomEvent {
return player; return player;
} }
/**
* Ensures compatibility with plugins like GuiRules.
*
* @return true
* @deprecated this will always return true because this event is only called if it was successful
*/
@Deprecated
public boolean isLogin() {
return true;
}
/** /**
* Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *

View File

@ -17,12 +17,11 @@ public class SpawnTeleportEvent extends AbstractTeleportEvent {
* Constructor. * Constructor.
* *
* @param player The player * @param player The player
* @param from The location the player is being teleported away from
* @param to The teleport destination * @param to The teleport destination
* @param isAuthenticated Whether or not the player is logged in * @param isAuthenticated Whether or not the player is logged in
*/ */
public SpawnTeleportEvent(Player player, Location from, Location to, boolean isAuthenticated) { public SpawnTeleportEvent(Player player, Location to, boolean isAuthenticated) {
super(false, player, from, to); super(false, player, to);
this.isAuthenticated = isAuthenticated; this.isAuthenticated = isAuthenticated;
} }

View File

@ -2,29 +2,37 @@ package fr.xephi.authme.hooks;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.plugin.messaging.PluginMessageListener;
/** import javax.inject.Inject;
*/
public class BungeeCordMessage implements PluginMessageListener { public class BungeeCordMessage implements PluginMessageListener {
private final AuthMe plugin; @Inject
private DataSource dataSource;
@Inject
private BukkitService bukkitService;
@Inject
private PlayerCache playerCache;
@Inject
private AuthMe plugin;
BungeeCordMessage() { }
/**
* Constructor for BungeeCordMessage.
*
* @param plugin The plugin instance
*/
public BungeeCordMessage(AuthMe plugin) {
this.plugin = plugin;
}
@Override @Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) { public void onPluginMessageReceived(String channel, Player player, byte[] message) {
@ -38,8 +46,7 @@ public class BungeeCordMessage implements PluginMessageListener {
final String[] args = str.split(";"); final String[] args = str.split(";");
final String act = args[0]; final String act = args[0];
final String name = args[1]; final String name = args[1];
final DataSource dataSource = plugin.getDataSource(); bukkitService.runTaskAsynchronously(new Runnable() {
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override @Override
public void run() { public void run() {
PlayerAuth auth = dataSource.getAuth(name); PlayerAuth auth = dataSource.getAuth(name);
@ -47,23 +54,33 @@ public class BungeeCordMessage implements PluginMessageListener {
return; return;
} }
if ("login".equals(act)) { if ("login".equals(act)) {
PlayerCache.getInstance().updatePlayer(auth); playerCache.updatePlayer(auth);
dataSource.setLogged(name); dataSource.setLogged(name);
ConsoleLogger.info("Player " + auth.getNickname() //START 03062016 sgdc3: should fix #731 but we need to recode this mess
+ " has logged in from one of your server!"); if (plugin.sessions.containsKey(name)) {
plugin.sessions.get(name).cancel();
plugin.sessions.remove(name);
}
//END
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
ConsoleLogger.info("Player " + auth.getNickname() + " has logged in from one of your server!");
}
} else if ("logout".equals(act)) { } else if ("logout".equals(act)) {
PlayerCache.getInstance().removePlayer(name); playerCache.removePlayer(name);
dataSource.setUnlogged(name); dataSource.setUnlogged(name);
ConsoleLogger.info("Player " + auth.getNickname() if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
+ " has logged out from one of your server!"); ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!");
}
} else if ("register".equals(act)) { } else if ("register".equals(act)) {
ConsoleLogger.info("Player " + auth.getNickname() if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
+ " has registered out from one of your server!"); ConsoleLogger.info("Player " + auth.getNickname() + " has registered out from one of your server!");
}
} else if ("changepassword".equals(act)) { } else if ("changepassword".equals(act)) {
final String password = args[2]; final String password = args[2];
final String salt = args.length >= 4 ? args[3] : null; final String salt = args.length >= 4 ? args[3] : null;
auth.setPassword(new HashedPassword(password, salt)); auth.setPassword(new HashedPassword(password, salt));
PlayerCache.getInstance().updatePlayer(auth); playerCache.updatePlayer(auth);
dataSource.updatePassword(auth); dataSource.updatePassword(auth);
} }

View File

@ -1,19 +1,18 @@
package fr.xephi.authme.hooks; package fr.xephi.authme.hooks;
import java.io.File; import com.earth2me.essentials.Essentials;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import fr.xephi.authme.ConsoleLogger;
import net.minelink.ctplus.CombatTagPlus;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import com.earth2me.essentials.Essentials; import javax.inject.Inject;
import com.onarandombox.MultiverseCore.MultiverseCore; import java.io.File;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import fr.xephi.authme.ConsoleLogger;
import net.minelink.ctplus.CombatTagPlus;
/** /**
* Hooks into third-party plugins and allows to perform actions on them. * Hooks into third-party plugins and allows to perform actions on them.
@ -30,6 +29,7 @@ public class PluginHooks {
* *
* @param pluginManager The server's plugin manager * @param pluginManager The server's plugin manager
*/ */
@Inject
public PluginHooks(PluginManager pluginManager) { public PluginHooks(PluginManager pluginManager) {
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
tryHookToCombatPlus(); tryHookToCombatPlus();
@ -77,13 +77,23 @@ public class PluginHooks {
return null; return null;
} }
/**
* Checks whether the player is an NPC.
*
* @param player The player to process
* @return True if player is NPC, false otherwise
*/
public boolean isNpc(Player player) {
return player.hasMetadata("NPC") || isNpcInCombatTagPlus(player);
}
/** /**
* Query the CombatTagPlus plugin whether the given player is an NPC. * Query the CombatTagPlus plugin whether the given player is an NPC.
* *
* @param player The player to verify * @param player The player to verify
* @return True if the player is an NPC according to CombatTagPlus, false if not or if the plugin is unavailable * @return True if the player is an NPC according to CombatTagPlus, false if not or if the plugin is unavailable
*/ */
public boolean isNpcInCombatTagPlus(Player player) { private boolean isNpcInCombatTagPlus(Player player) {
return combatTagPlus != null && combatTagPlus.getNpcPlayerHelper().isNpc(player); return combatTagPlus != null && combatTagPlus.getNpcPlayerHelper().isNpc(player);
} }

View File

@ -0,0 +1,324 @@
package fr.xephi.authme.initialization;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import fr.xephi.authme.settings.NewSetting;
import javax.annotation.PostConstruct;
import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Dependency injector of AuthMe: initializes and injects services and tasks.
* <p>
* Only constructor and field injection are supported, indicated with the JSR330
* {@link javax.inject.Inject @Inject} annotation.
* <p>
* {@link PostConstruct @PostConstruct} methods are recognized and invoked upon
* instantiation. Note that the parent classes are <i>not</i> scanned for such methods.
*/
public class AuthMeServiceInitializer {
private final Set<String> ALLOWED_PACKAGES;
private final Map<Class<?>, Object> objects;
/**
* Constructor.
*
* @param allowedPackages list of allowed packages. Only classes whose package
* starts with any of the given entries will be instantiated
*/
public AuthMeServiceInitializer(String... allowedPackages) {
ALLOWED_PACKAGES = ImmutableSet.copyOf(allowedPackages);
objects = new HashMap<>();
objects.put(getClass(), this);
}
/**
* Retrieves or instantiates an object of the given type.
*
* @param clazz the class to retrieve the value for
* @param <T> the class' type
* @return object of the class' type
*/
public <T> T get(Class<T> clazz) {
return get(clazz, new HashSet<Class<?>>());
}
/**
* Register an object with a custom class (supertype). Use this for example to specify a
* concrete implementation of an interface or an abstract class.
*
* @param clazz the class to register the object for
* @param object the object
* @param <T> the class' type
*/
public <T> void register(Class<? super T> clazz, T object) {
if (objects.containsKey(clazz)) {
throw new IllegalStateException("There is already an object present for " + clazz);
}
Preconditions.checkNotNull(object);
objects.put(clazz, object);
}
/**
* Associate an annotation with a value.
*
* @param annotation the annotation
* @param value the value
*/
public void provide(Class<? extends Annotation> annotation, Object value) {
if (objects.containsKey(annotation)) {
throw new IllegalStateException("Annotation @" + annotation.getClass().getSimpleName()
+ " already registered");
}
Preconditions.checkNotNull(value);
objects.put(annotation, value);
}
/**
* Creates a new instance of the given class and does <i>not</i> keep track of it afterwards,
* unlike {@link #get(Class)} (singleton scope).
*
* @param clazz the class to instantiate
* @param <T> the class' type
* @return new instance of class T
*/
public <T> T newInstance(Class<T> clazz) {
return instantiate(clazz, new HashSet<Class<?>>());
}
/**
* Returns an instance of the given class if available. This simply returns the instance if present and
* otherwise {@code null}. Calling this method will not instantiate anything.
*
* @param clazz the class to retrieve the instance for
* @param <T> the class' type
* @return instance or null if none available
*/
public <T> T getIfAvailable(Class<T> clazz) {
if (Annotation.class.isAssignableFrom(clazz)) {
throw new UnsupportedOperationException("Annotations may not be retrieved in this way!");
}
return clazz.cast(objects.get(clazz));
}
/**
* Returns an instance of the given class by retrieving it or by instantiating it if not yet present.
*
* @param clazz the class to retrieve a value for
* @param traversedClasses the list of traversed classes
* @param <T> the class' type
* @return instance or associated value (for annotations)
*/
private <T> T get(Class<T> clazz, Set<Class<?>> traversedClasses) {
if (Annotation.class.isAssignableFrom(clazz)) {
throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!");
} else if (objects.containsKey(clazz)) {
return clazz.cast(objects.get(clazz));
}
// First time we come across clazz, need to instantiate it. Validate that we can do so
validatePackage(clazz);
validateInstantiable(clazz);
// Add the clazz to the list of traversed classes in a new Set, so each path we take has its own Set.
traversedClasses = new HashSet<>(traversedClasses);
traversedClasses.add(clazz);
T object = instantiate(clazz, traversedClasses);
storeObject(object);
return object;
}
/**
* Performs a reload on all applicable instances which are registered.
* Requires that the {@link NewSetting settings} instance be registered.
* <p>
* Note that the order in which these classes are reloaded is not guaranteed.
*/
public void performReloadOnServices() {
NewSetting settings = (NewSetting) objects.get(NewSetting.class);
if (settings == null) {
throw new IllegalStateException("Settings instance is null");
}
for (Object object : objects.values()) {
if (object instanceof Reloadable) {
((Reloadable) object).reload();
} else if (object instanceof SettingsDependent) {
((SettingsDependent) object).loadSettings(settings);
}
}
}
/**
* Instantiates the given class by locating its @Inject elements and retrieving
* or instantiating the required instances.
*
* @param clazz the class to instantiate
* @param traversedClasses collection of classes already traversed
* @param <T> the class' type
* @return the instantiated object
*/
private <T> T instantiate(Class<T> clazz, Set<Class<?>> traversedClasses) {
Injection<T> injection = firstNotNull(
ConstructorInjection.provide(clazz), FieldInjection.provide(clazz), InstantiationFallback.provide(clazz));
if (injection == null) {
throw new IllegalStateException("Did not find injection method for " + clazz + ". Make sure you have "
+ "a constructor with @Inject or fields with @Inject. Fields with @Inject require "
+ "the default constructor");
}
validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
Object[] dependencies = resolveDependencies(injection, traversedClasses);
T object = injection.instantiateWith(dependencies);
executePostConstructMethod(object);
return object;
}
/**
* Resolves the dependencies for the given class instantiation, i.e. returns a collection that satisfy
* the class' dependencies by retrieving elements or instantiating them where necessary.
*
* @param injection the injection parameters
* @param traversedClasses collection of traversed classes
* @return array with the parameters to use in the constructor
*/
private Object[] resolveDependencies(Injection<?> injection, Set<Class<?>> traversedClasses) {
Class<?>[] dependencies = injection.getDependencies();
Class<?>[] annotations = injection.getDependencyAnnotations();
Object[] values = new Object[dependencies.length];
for (int i = 0; i < dependencies.length; ++i) {
if (annotations[i] == null) {
values[i] = get(dependencies[i], traversedClasses);
} else {
Object value = objects.get(annotations[i]);
if (value == null) {
throw new IllegalStateException("Value for field with @" + annotations[i].getSimpleName()
+ " must be registered beforehand");
}
values[i] = value;
}
}
return values;
}
/**
* Stores the given object with its class as key. Throws an exception if the key already has
* a value associated to it.
*
* @param object the object to store
*/
private void storeObject(Object object) {
if (objects.containsKey(object.getClass())) {
throw new IllegalStateException("There is already an object present for " + object.getClass());
}
Preconditions.checkNotNull(object);
objects.put(object.getClass(), object);
}
/**
* Validates that none of the dependencies' types are present in the given collection
* of traversed classes. This prevents circular dependencies.
*
* @param dependencies the dependencies of the class
* @param traversedClasses the collection of traversed classes
*/
private static void validateInjectionHasNoCircularDependencies(Class<?>[] dependencies,
Set<Class<?>> traversedClasses) {
for (Class<?> clazz : dependencies) {
if (traversedClasses.contains(clazz)) {
throw new IllegalStateException("Found cyclic dependency - already traversed '" + clazz
+ "' (full traversal list: " + traversedClasses + ")");
}
}
}
/**
* Validates the package of a parameter type to ensure that it is part of the allowed packages.
* This ensures that we don't try to instantiate things that are beyond our reach in case some
* external parameter type has not been registered.
*
* @param clazz the class to validate
*/
private void validatePackage(Class<?> clazz) {
if (clazz.getPackage() == null) {
throw new IllegalStateException("Primitive types must be provided explicitly (or use an annotation).");
}
String packageName = clazz.getPackage().getName();
for (String allowedPackage : ALLOWED_PACKAGES) {
if (packageName.startsWith(allowedPackage)) {
return;
}
}
throw new IllegalStateException("Class " + clazz + " with package " + packageName + " is outside of the "
+ "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
}
/**
* Executes an object's method annotated with {@link PostConstruct} if present.
* Throws an exception if there are multiple such methods, or if the method is static.
*
* @param object the object to execute the post construct method for
*/
private static void executePostConstructMethod(Object object) {
Method postConstructMethod = getAndValidatePostConstructMethod(object.getClass());
if (postConstructMethod != null) {
try {
postConstructMethod.setAccessible(true);
postConstructMethod.invoke(object);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new UnsupportedOperationException("Error executing @PostConstruct method", e);
}
}
}
private static void validateInstantiable(Class<?> clazz) {
if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated");
}
}
/**
* Validate and locate the given class' post construct method. Returns {@code null} if none present.
*
* @param clazz the class to search
* @return post construct method, or null
*/
private static Method getAndValidatePostConstructMethod(Class<?> clazz) {
Method postConstructMethod = null;
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
if (postConstructMethod != null) {
throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz);
} else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. "
+ "Invalid method in " + clazz);
} else if (method.getReturnType() != void.class) {
throw new IllegalStateException("@PostConstruct method must have return type void. "
+ "Offending class: " + clazz);
} else {
postConstructMethod = method;
}
}
}
return postConstructMethod;
}
@SafeVarargs
private static <T> Injection<T> firstNotNull(Provider<? extends Injection<T>>... providers) {
for (Provider<? extends Injection<T>> provider : providers) {
Injection<T> object = provider.get();
if (object != null) {
return object;
}
}
return null;
}
}

View File

@ -0,0 +1,86 @@
package fr.xephi.authme.initialization;
import com.google.common.base.Preconditions;
import javax.inject.Inject;
import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Functionality for constructor injection.
*/
public class ConstructorInjection<T> implements Injection<T> {
private final Constructor<T> constructor;
private ConstructorInjection(Constructor<T> constructor) {
this.constructor = constructor;
}
@Override
public Class<?>[] getDependencies() {
return constructor.getParameterTypes();
}
@Override
public Class<?>[] getDependencyAnnotations() {
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
Class<?>[] annotations = new Class<?>[parameterAnnotations.length];
for (int i = 0; i < parameterAnnotations.length; ++i) {
annotations[i] = parameterAnnotations[i].length > 0
? parameterAnnotations[i][0].annotationType()
: null;
}
return annotations;
}
@Override
public T instantiateWith(Object... values) {
validateNoNullValues(values);
try {
return constructor.newInstance(values);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new UnsupportedOperationException(e);
}
}
public static <T> Provider<ConstructorInjection<T>> provide(final Class<T> clazz) {
return new Provider<ConstructorInjection<T>>() {
@Override
public ConstructorInjection<T> get() {
Constructor<T> constructor = getInjectionConstructor(clazz);
return constructor == null ? null : new ConstructorInjection<>(constructor);
}
};
}
/**
* Gets the first found constructor annotated with {@link Inject} of the given class
* and marks it as accessible.
*
* @param clazz the class to process
* @param <T> the class' type
* @return injection constructor for the class, null if not applicable
*/
@SuppressWarnings("unchecked")
private static <T> Constructor<T> getInjectionConstructor(Class<T> clazz) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.isAnnotationPresent(Inject.class)) {
constructor.setAccessible(true);
return (Constructor<T>) constructor;
}
}
return null;
}
private static void validateNoNullValues(Object[] array) {
for (Object entry : array) {
Preconditions.checkNotNull(entry);
}
}
}

View File

@ -0,0 +1,14 @@
package fr.xephi.authme.initialization;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for specifying the plugin's data folder.
*/
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataFolder {
}

View File

@ -0,0 +1,128 @@
package fr.xephi.authme.initialization;
import com.google.common.base.Preconditions;
import javax.inject.Inject;
import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Functionality for field injection.
*/
public class FieldInjection<T> implements Injection<T> {
private final Field[] fields;
private final Constructor<T> defaultConstructor;
private FieldInjection(Constructor<T> defaultConstructor, Collection<Field> fields) {
this.fields = fields.toArray(new Field[fields.size()]);
this.defaultConstructor = defaultConstructor;
}
@Override
public Class<?>[] getDependencies() {
Class<?>[] types = new Class<?>[fields.length];
for (int i = 0; i < fields.length; ++i) {
types[i] = fields[i].getType();
}
return types;
}
@Override
public Class<?>[] getDependencyAnnotations() {
Class<?>[] annotations = new Class<?>[fields.length];
for (int i = 0; i < fields.length; ++i) {
annotations[i] = getFirstNonInjectAnnotation(fields[i]);
}
return annotations;
}
@Override
public T instantiateWith(Object... values) {
Preconditions.checkArgument(values.length == fields.length,
"The number of values must be equal to the number of fields");
T instance;
try {
instance = defaultConstructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new UnsupportedOperationException(e);
}
for (int i = 0; i < fields.length; ++i) {
try {
Preconditions.checkNotNull(values[i]);
fields[i].set(instance, values[i]);
} catch (IllegalAccessException e) {
throw new UnsupportedOperationException(e);
}
}
return instance;
}
/**
* Returns a provider for a {@code FieldInjection<T>} instance, i.e. a provides an object
* with which field injection can be performed on the given class if applicable. The provided
* value is {@code null} if field injection cannot be applied to the class.
*
* @param clazz the class to provide field injection for
* @param <T> the class' type
* @return field injection provider for the given class, or null if not applicable
*/
public static <T> Provider<FieldInjection<T>> provide(final Class<T> clazz) {
return new Provider<FieldInjection<T>>() {
@Override
public FieldInjection<T> get() {
Constructor<T> constructor = getDefaultConstructor(clazz);
if (constructor == null) {
return null;
}
List<Field> fields = getInjectionFields(clazz);
return fields.isEmpty() ? null : new FieldInjection<>(constructor, fields);
}
};
}
private static List<Field> getInjectionFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Inject.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException(String.format("Field '%s' in class '%s' is static but "
+ "annotated with @Inject", field.getName(), clazz.getSimpleName()));
}
field.setAccessible(true);
fields.add(field);
}
}
return fields;
}
private static Class<?> getFirstNonInjectAnnotation(Field field) {
for (Annotation annotation : field.getAnnotations()) {
if (annotation.annotationType() != Inject.class) {
return annotation.annotationType();
}
}
return null;
}
@SuppressWarnings("unchecked")
private static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) {
try {
Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
defaultConstructor.setAccessible(true);
return (Constructor<T>) defaultConstructor;
} catch (NoSuchMethodException ignore) {
// no default constructor available
}
return null;
}
}

View File

@ -0,0 +1,36 @@
package fr.xephi.authme.initialization;
/**
* Common interface for all injection methods.
*
* @param <T> the type of the concerned object
*/
public interface Injection<T> {
/**
* Returns the dependencies that must be provided to instantiate the given item.
*
* @return list of dependencies
* @see #instantiateWith
*/
Class<?>[] getDependencies();
/**
* Returns the annotation on each dependency if available. The indices of this
* array correspond to the ones of {@link #getDependencies()}. If no annotation
* is available, {@code null} is stored. If multiple annotations are present, only
* one is stored (no guarantee on which one).
*
* @return annotation for each dependency
*/
Class<?>[] getDependencyAnnotations();
/**
* Creates a new instance with the given values as dependencies. The given values
* must correspond to {@link #getDependencies()} in size, order and type.
*
* @param values the values to set for the dependencies
* @return resulting object
*/
T instantiateWith(Object... values);
}

View File

@ -0,0 +1,85 @@
package fr.xephi.authme.initialization;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Provider;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Fallback instantiation method for classes with an accessible no-args constructor
* and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}.
*/
public class InstantiationFallback<T> implements Injection<T> {
private final Constructor<T> constructor;
private InstantiationFallback(Constructor<T> constructor) {
this.constructor = constructor;
}
@Override
public Class<?>[] getDependencies() {
return new Class<?>[0];
}
@Override
public Class<?>[] getDependencyAnnotations() {
return new Class<?>[0];
}
@Override
public T instantiateWith(Object... values) {
if (values == null || values.length > 0) {
throw new UnsupportedOperationException("Instantiation fallback cannot have parameters");
}
try {
return constructor.newInstance();
} catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
throw new UnsupportedOperationException(e);
}
}
/**
* Returns an instantiation fallback if the class is applicable.
*
* @param clazz the class
* @param <T> the class' type
* @return instantiation fallback provider for the given class, or null if not applicable
*/
public static <T> Provider<InstantiationFallback<T>> provide(final Class<T> clazz) {
return new Provider<InstantiationFallback<T>>() {
@Override
public InstantiationFallback<T> get() {
Constructor<T> noArgsConstructor = getNoArgsConstructor(clazz);
// Return fallback only if we have no args constructor and no @Inject annotation anywhere
if (noArgsConstructor != null
&& !isInjectionAnnotationPresent(clazz.getDeclaredConstructors())
&& !isInjectionAnnotationPresent(clazz.getDeclaredFields())
&& !isInjectionAnnotationPresent(clazz.getDeclaredMethods())) {
return new InstantiationFallback<>(noArgsConstructor);
}
return null;
}
};
}
private static <T> Constructor<T> getNoArgsConstructor(Class<T> clazz) {
try {
// Note ljacqu 20160504: getConstructor(), unlike getDeclaredConstructor(), only considers public members
return clazz.getConstructor();
} catch (NoSuchMethodException e) {
return null;
}
}
private static <A extends AccessibleObject> boolean isInjectionAnnotationPresent(A[] accessibles) {
for (A accessible : accessibles) {
if (accessible.isAnnotationPresent(Inject.class) || accessible.isAnnotationPresent(PostConstruct.class)) {
return true;
}
}
return false;
}
}

View File

@ -1,5 +1,7 @@
package fr.xephi.authme; package fr.xephi.authme.initialization;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.PluginSettings;

View File

@ -0,0 +1,13 @@
package fr.xephi.authme.initialization;
/**
* Interface for reloadable entities.
*/
public interface Reloadable {
/**
* Performs the reload action.
*/
void reload();
}

View File

@ -0,0 +1,16 @@
package fr.xephi.authme.initialization;
import fr.xephi.authme.settings.NewSetting;
/**
* Interface for classes that keep a local copy of certain settings.
*/
public interface SettingsDependent {
/**
* Loads the needed settings.
*
* @param settings the settings instance
*/
void loadSettings(NewSetting settings);
}

View File

@ -5,18 +5,23 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import javax.inject.Inject;
public class AuthMeBlockListener implements Listener { public class AuthMeBlockListener implements Listener {
@Inject
private ListenerService listenerService;
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
if (ListenerService.shouldCancelEvent(event.getPlayer())) { if (listenerService.shouldCancelEvent(event.getPlayer())) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
if (ListenerService.shouldCancelEvent(event.getPlayer())) { if (listenerService.shouldCancelEvent(event.getPlayer())) {
event.setCancelled(true); event.setCancelled(true);
} }
} }

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.listener; package fr.xephi.authme.listener;
import fr.xephi.authme.ConsoleLogger;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
@ -14,29 +15,32 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.projectiles.ProjectileSource;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent;
public class AuthMeEntityListener implements Listener { public class AuthMeEntityListener implements Listener {
private static Method getShooter; private final ListenerService listenerService;
private static boolean shooterIsProjectileSource; private Method getShooter;
private boolean shooterIsLivingEntity;
public AuthMeEntityListener() { @Inject
AuthMeEntityListener(ListenerService listenerService) {
this.listenerService = listenerService;
try { try {
Method m = Projectile.class.getDeclaredMethod("getShooter"); getShooter = Projectile.class.getDeclaredMethod("getShooter");
shooterIsProjectileSource = m.getReturnType() != LivingEntity.class; shooterIsLivingEntity = getShooter.getReturnType() == LivingEntity.class;
} catch (Exception ignored) { } catch (NoSuchMethodException | SecurityException e) {
ConsoleLogger.logException("Cannot load getShooter() method on Projectile class", e);
} }
} }
// Note #360: npc status can be used to bypass security!!! // Note #360: npc status can be used to bypass security!!!
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityDamage(EntityDamageEvent event) { public void onEntityDamage(EntityDamageEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.getEntity().setFireTicks(0); event.getEntity().setFireTicks(0);
event.setDamage(0); event.setDamage(0);
event.setCancelled(true); event.setCancelled(true);
@ -45,7 +49,7 @@ public class AuthMeEntityListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityTarget(EntityTargetEvent event) { public void onEntityTarget(EntityTargetEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setTarget(null); event.setTarget(null);
event.setCancelled(true); event.setCancelled(true);
} }
@ -53,21 +57,21 @@ public class AuthMeEntityListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onDamage(EntityDamageByEntityEvent event) { public void onDamage(EntityDamageByEntityEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onFoodLevelChange(FoodLevelChangeEvent event) { public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void entityRegainHealthEvent(EntityRegainHealthEvent event) { public void entityRegainHealthEvent(EntityRegainHealthEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setAmount(0); event.setAmount(0);
event.setCancelled(true); event.setCancelled(true);
} }
@ -75,53 +79,48 @@ public class AuthMeEntityListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityInteract(EntityInteractEvent event) { public void onEntityInteract(EntityInteractEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onLowestEntityInteract(EntityInteractEvent event) { public void onLowestEntityInteract(EntityInteractEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
// TODO #568: Need to check this, player can't throw snowball but the item is taken. // TODO #733: Player can't throw snowball but the item is taken.
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onProjectileLaunch(ProjectileLaunchEvent event) { public void onProjectileLaunch(ProjectileLaunchEvent event) {
if (event.getEntity() == null) { if (event.getEntity() == null) {
return; return;
} }
Player player = null;
Projectile projectile = event.getEntity(); Projectile projectile = event.getEntity();
if (shooterIsProjectileSource) { // In the Bukkit API prior to 1.7, getShooter() returns a LivingEntity instead of a ProjectileSource
ProjectileSource shooter = projectile.getShooter(); Object shooterRaw = null;
if (shooter == null || !(shooter instanceof Player)) { if (shooterIsLivingEntity) {
return;
}
player = (Player) shooter;
} else {
// TODO #568 20151220: Invoking getShooter() with null but method isn't static
try { try {
if (getShooter == null) { if (getShooter == null) {
getShooter = Projectile.class.getMethod("getShooter"); getShooter = Projectile.class.getMethod("getShooter");
} }
Object obj = getShooter.invoke(null); shooterRaw = getShooter.invoke(projectile);
player = (Player) obj; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
} catch (Exception ignored) { ConsoleLogger.logException("Error getting shooter", e);
} }
} else {
shooterRaw = projectile.getShooter();
} }
if (shooterRaw instanceof Player && listenerService.shouldCancelEvent((Player) shooterRaw)) {
if (ListenerService.shouldCancelEvent(player)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL)
public void onShoot(EntityShootBowEvent event) { public void onShoot(EntityShootBowEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }

View File

@ -1,32 +1,18 @@
package fr.xephi.authme.listener; package fr.xephi.authme.listener;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import fr.xephi.authme.AntiBot; import fr.xephi.authme.AntiBot;
import fr.xephi.authme.AntiBot.AntiBotStatus;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -54,11 +40,12 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent; import org.bukkit.event.player.PlayerShearEntityEvent;
import javax.inject.Inject;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS; import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT; import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT;
/** /**
@ -67,107 +54,65 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAU
public class AuthMePlayerListener implements Listener { public class AuthMePlayerListener implements Listener {
public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<String, Boolean> causeByAuthMe = new ConcurrentHashMap<>();
private final AuthMe plugin;
private final NewSetting settings;
private final Messages m;
private final DataSource dataSource;
private final AntiBot antiBot;
private final Management management;
private final BukkitService bukkitService;
private final ValidationService validationService;
public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, @Inject
AntiBot antiBot, Management management, BukkitService bukkitService, private NewSetting settings;
ValidationService validationService) { @Inject
this.plugin = plugin; private Messages m;
this.settings = settings; @Inject
this.m = messages; private DataSource dataSource;
this.dataSource = dataSource; @Inject
this.antiBot = antiBot; private AntiBot antiBot;
this.management = management; @Inject
this.bukkitService = bukkitService; private Management management;
this.validationService = validationService; @Inject
} private BukkitService bukkitService;
@Inject
private void handleChat(AsyncPlayerChatEvent event) { private SpawnLoader spawnLoader;
if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) { @Inject
return; private OnJoinVerifier onJoinVerifier;
} @Inject
private ListenerService listenerService;
final Player player = event.getPlayer();
if (shouldCancelEvent(player)) {
event.setCancelled(true);
sendLoginOrRegisterMessage(player);
} else if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) {
for (Player p : bukkitService.getOnlinePlayers()) {
if (!PlayerCache.getInstance().isAuthenticated(p.getName())) {
event.getRecipients().remove(p);
}
}
}
}
private void sendLoginOrRegisterMessage(final Player player) {
bukkitService.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
if (dataSource.isAuthAvailable(player.getName().toLowerCase())) {
m.send(player, MessageKey.LOGIN_MESSAGE);
} else {
if (settings.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)) {
m.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
} else {
m.send(player, MessageKey.REGISTER_MESSAGE);
}
}
}
});
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String cmd = event.getMessage().split(" ")[0].toLowerCase(); String cmd = event.getMessage().split(" ")[0].toLowerCase();
if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) { if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && cmd.equals("/motd")) {
return;
}
if (!settings.getProperty(RegistrationSettings.FORCE)
&& settings.getProperty(ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL)) {
return; return;
} }
if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) { if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) {
return; return;
} }
if (Utils.checkAuth(event.getPlayer())) { final Player player = event.getPlayer();
return; if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true);
m.send(player, MessageKey.DENIED_COMMAND);
} }
event.setCancelled(true);
sendLoginOrRegisterMessage(event.getPlayer());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL)
public void onPlayerNormalChat(AsyncPlayerChatEvent event) {
handleChat(event);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onPlayerHighChat(AsyncPlayerChatEvent event) {
handleChat(event);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerHighestChat(AsyncPlayerChatEvent event) {
handleChat(event);
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerEarlyChat(AsyncPlayerChatEvent event) { public void onPlayerChat(AsyncPlayerChatEvent event) {
handleChat(event); if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) {
} return;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) final Player player = event.getPlayer();
public void onPlayerLowChat(AsyncPlayerChatEvent event) { if (listenerService.shouldCancelEvent(player)) {
handleChat(event); event.setCancelled(true);
m.send(player, MessageKey.DENIED_CHAT);
} else if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) {
Set<Player> recipients = event.getRecipients();
Iterator<Player> iter = recipients.iterator();
while (iter.hasNext()) {
Player p = iter.next();
if (listenerService.shouldCancelEvent(p)) {
iter.remove();
}
}
if (recipients.size() == 0) {
event.setCancelled(true);
}
}
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
@ -180,20 +125,22 @@ public class AuthMePlayerListener implements Listener {
* Limit player X and Z movements to 1 block * Limit player X and Z movements to 1 block
* Deny player Y+ movements (allows falling) * Deny player Y+ movements (allows falling)
*/ */
if (event.getFrom().getBlockX() == event.getTo().getBlockX() Location from = event.getFrom();
&& event.getFrom().getBlockZ() == event.getTo().getBlockZ() Location to = event.getTo();
&& event.getFrom().getY() - event.getTo().getY() >= 0) { if (from.getBlockX() == to.getBlockX()
&& from.getBlockZ() == to.getBlockZ()
&& from.getY() - to.getY() >= 0) {
return; return;
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (Utils.checkAuth(player)) { if (!listenerService.shouldCancelEvent(player)) {
return; return;
} }
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) { if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
// "cancel" the event
event.setTo(event.getFrom()); event.setTo(event.getFrom());
// sgdc3 TODO: remove this, maybe we should set the effect every x ticks, idk!
if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) { if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
player.setFlySpeed(0.0f); player.setFlySpeed(0.0f);
player.setWalkSpeed(0.0f); player.setWalkSpeed(0.0f);
@ -205,7 +152,7 @@ public class AuthMePlayerListener implements Listener {
return; return;
} }
Location spawn = plugin.getSpawnLocation(player); Location spawn = spawnLoader.getSpawnLocation(player);
if (spawn != null && spawn.getWorld() != null) { if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) { if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn); player.teleport(spawn);
@ -245,149 +192,82 @@ public class AuthMePlayerListener implements Listener {
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (player == null) { if (player != null) {
return; // Schedule login task so works after the prelogin
// (Fix found by Koolaid5000)
bukkitService.runTask(new Runnable() {
@Override
public void run() {
management.performJoin(player);
}
});
} }
if (settings.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE)
&& !player.hasPermission(PlayerStatePermission.BYPASS_FORCE_SURVIVAL.getNode())) {
player.setGameMode(GameMode.SURVIVAL);
}
// Shedule login task so works after the prelogin
// (Fix found by Koolaid5000)
bukkitService.runTask(new Runnable() {
@Override
public void run() {
management.performJoin(player);
}
});
} }
// Note ljacqu 20160528: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
// e.g. CraftBukkit does not. So we need to run crucial things in onPlayerLogin, too
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPreLogin(AsyncPlayerPreLoginEvent event) { public void onPreLogin(AsyncPlayerPreLoginEvent event) {
PlayerAuth auth = dataSource.getAuth(event.getName());
if (settings.getProperty(RegistrationSettings.PREVENT_OTHER_CASE) && auth != null && auth.getRealName() != null) {
String realName = auth.getRealName();
if (!realName.isEmpty() && !"Player".equals(realName) && !realName.equals(event.getName())) {
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CASE, realName, event.getName()));
return;
}
if (realName.isEmpty() || "Player".equals(realName)) {
dataSource.updateRealName(event.getName().toLowerCase(), event.getName());
}
}
if (auth == null && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
String playerIp = event.getAddress().getHostAddress();
if (!validationService.isCountryAdmitted(playerIp)) {
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
event.setKickMessage(m.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR));
return;
}
}
final String name = event.getName().toLowerCase(); final String name = event.getName().toLowerCase();
final Player player = bukkitService.getPlayerExact(name); final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName());
// Check if forceSingleSession is set to true, so kick player that has
// joined with same nick of online player try {
if (player != null && settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) { // Potential performance improvement: make checkAntiBot not require `isAuthAvailable` info and use
// "checkKickNonRegistered" as last -> no need to query the DB before checking antibot / name
onJoinVerifier.checkAntibot(name, isAuthAvailable);
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkIsValidName(name);
// Note #760: Single session must be checked here - checking with PlayerLoginEvent is too late and
// the first connection will have been kicked. This means this feature doesn't work on CraftBukkit.
onJoinVerifier.checkSingleSession(name);
} catch (FailedVerificationException e) {
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
event.setKickMessage(m.retrieveSingle(MessageKey.USERNAME_ALREADY_ONLINE_ERROR));
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name);
if (limbo != null && PlayerCache.getInstance().isAuthenticated(name)) {
Utils.addNormal(player, limbo.getGroup());
LimboCache.getInstance().deleteLimboPlayer(name);
}
} }
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerLogin(PlayerLoginEvent event) { public void onPlayerLogin(PlayerLoginEvent event) {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (player == null || Utils.isUnrestricted(player)) { if (Utils.isUnrestricted(player)) {
return; return;
} } else if (onJoinVerifier.refusePlayerForFullServer(event)) {
return;
// Get the permissions manager } else if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
PermissionsManager permsMan = plugin.getPermissionsManager();
if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL) {
if (permsMan.hasPermission(player, PlayerStatePermission.IS_VIP)) {
int playersOnline = bukkitService.getOnlinePlayers().size();
if (playersOnline > plugin.getServer().getMaxPlayers()) {
event.allow();
} else {
Player pl = plugin.generateKickPlayer(bukkitService.getOnlinePlayers());
if (pl != null) {
pl.kickPlayer(m.retrieveSingle(MessageKey.KICK_FOR_VIP));
event.allow();
} else {
ConsoleLogger.info("The player " + event.getPlayer().getName() + " tried to join, but the server was full");
event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER));
event.setResult(PlayerLoginEvent.Result.KICK_FULL);
}
}
} else {
event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER));
event.setResult(PlayerLoginEvent.Result.KICK_FULL);
return;
}
}
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return; return;
} }
final String name = player.getName().toLowerCase(); final String name = player.getName().toLowerCase();
boolean isAuthAvailable = dataSource.isAuthAvailable(name); final PlayerAuth auth = dataSource.getAuth(player.getName());
final boolean isAuthAvailable = (auth != null);
if (antiBot.getAntiBotStatus() == AntiBotStatus.ACTIVE && !isAuthAvailable) { try {
event.setKickMessage(m.retrieveSingle(MessageKey.KICK_ANTIBOT)); onJoinVerifier.checkAntibot(name, isAuthAvailable);
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkIsValidName(name);
onJoinVerifier.checkNameCasing(player, auth);
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event);
} catch (FailedVerificationException e) {
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER); event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return; return;
} }
if (settings.getProperty(RestrictionSettings.KICK_NON_REGISTERED) && !isAuthAvailable) { antiBot.handlePlayerJoin(player);
event.setKickMessage(m.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return;
}
if (name.length() > Settings.getMaxNickLength || name.length() < Settings.getMinNickLength) {
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_LENGTH));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return;
}
if (!Settings.nickPattern.matcher(player.getName()).matches() || name.equalsIgnoreCase("Player")) {
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CHARACTERS).replace("REG_EX", Settings.getNickRegex));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return;
}
antiBot.checkAntiBot(player);
if (settings.getProperty(HooksSettings.BUNGEECORD)) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("IP");
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player == null) {
return;
}
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) { if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
event.setQuitMessage(null); event.setQuitMessage(null);
} }
if (antiBot.antibotKicked.contains(player.getName())) {
return;
}
management.performQuit(player, false); management.performQuit(player, false);
} }
@ -395,42 +275,28 @@ public class AuthMePlayerListener implements Listener {
public void onPlayerKick(PlayerKickEvent event) { public void onPlayerKick(PlayerKickEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player == null) { if (!antiBot.antibotKicked.contains(player.getName())) {
return; management.performQuit(player, true);
} }
if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)
&& event.getReason().equals(m.retrieveSingle(MessageKey.USERNAME_ALREADY_ONLINE_ERROR))) {
event.setCancelled(true);
return;
}
plugin.getManagement().performQuit(player, true);
} }
/*
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
* Note #360: npc status can be used to bypass security!!!
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerPickupItem(PlayerPickupItemEvent event) { public void onPlayerPickupItem(PlayerPickupItemEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { public void onPlayerConsumeItem(PlayerItemConsumeEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@ -439,7 +305,7 @@ public class AuthMePlayerListener implements Listener {
public void onPlayerInventoryOpen(InventoryOpenEvent event) { public void onPlayerInventoryOpen(InventoryOpenEvent event) {
final Player player = (Player) event.getPlayer(); final Player player = (Player) event.getPlayer();
if (!ListenerService.shouldCancelEvent(player)) { if (!listenerService.shouldCancelEvent(player)) {
return; return;
} }
event.setCancelled(true); event.setCancelled(true);
@ -448,7 +314,7 @@ public class AuthMePlayerListener implements Listener {
* @note little hack cause InventoryOpenEvent cannot be cancelled for * @note little hack cause InventoryOpenEvent cannot be cancelled for
* real, cause no packet is send to server by client for the main inv * real, cause no packet is send to server by client for the main inv
*/ */
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { bukkitService.scheduleSyncDelayedTask(new Runnable() {
@Override @Override
public void run() { public void run() {
player.closeInventory(); player.closeInventory();
@ -458,41 +324,43 @@ public class AuthMePlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInventoryClick(InventoryClickEvent event) { public void onPlayerInventoryClick(InventoryClickEvent event) {
if (event.getWhoClicked() == null) if (event.getWhoClicked() == null) {
return; return;
if (!(event.getWhoClicked() instanceof Player)) }
if (!(event.getWhoClicked() instanceof Player)) {
return; return;
if (Utils.checkAuth((Player) event.getWhoClicked())) }
return; Player player = (Player) event.getWhoClicked();
if (Utils.isNPC((Player) event.getWhoClicked())) if (!listenerService.shouldCancelEvent(player)) {
return; return;
}
event.setCancelled(true); event.setCancelled(true);
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerHitPlayerEvent(EntityDamageByEntityEvent event) { public void onPlayerHitPlayerEvent(EntityDamageByEntityEvent event) {
if (ListenerService.shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerDropItem(PlayerDropItemEvent event) { public void onPlayerDropItem(PlayerDropItemEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerBedEnter(PlayerBedEnterEvent event) { public void onPlayerBedEnter(PlayerBedEnterEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@ -500,21 +368,24 @@ public class AuthMePlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onSignChange(SignChangeEvent event) { public void onSignChange(SignChangeEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (ListenerService.shouldCancelEvent(player)) { if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
// TODO: check this, why do we need to update the quit loc? -sgdc3
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) { public void onPlayerRespawn(PlayerRespawnEvent event) {
if (!shouldCancelEvent(event)) { if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
if (!listenerService.shouldCancelEvent(event)) {
return; return;
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
Location spawn = plugin.getSpawnLocation(player); Location spawn = spawnLoader.getSpawnLocation(player);
if (Settings.isSaveQuitLocationEnabled && dataSource.isAuthAvailable(name)) { if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION) && dataSource.isAuthAvailable(name)) {
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.realName(player.getName()) .realName(player.getName())
@ -529,15 +400,16 @@ public class AuthMePlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerShear(PlayerShearEntityEvent event) { public void onPlayerShear(PlayerShearEntityEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerFish(PlayerFishEvent event) { public void onPlayerFish(PlayerFishEvent event) {
if (shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
} }

View File

@ -5,14 +5,19 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerEditBookEvent; import org.bukkit.event.player.PlayerEditBookEvent;
import javax.inject.Inject;
/** /**
* Listener of player events for events introduced in Minecraft 1.6. * Listener of player events for events introduced in Minecraft 1.6.
*/ */
public class AuthMePlayerListener16 implements Listener { public class AuthMePlayerListener16 implements Listener {
@Inject
private ListenerService listenerService;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerEditBook(PlayerEditBookEvent event) { public void onPlayerEditBook(PlayerEditBookEvent event) {
if (ListenerService.shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }

View File

@ -5,14 +5,19 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import javax.inject.Inject;
/** /**
* Listener of player events for events introduced in Minecraft 1.8. * Listener of player events for events introduced in Minecraft 1.8.
*/ */
public class AuthMePlayerListener18 implements Listener { public class AuthMePlayerListener18 implements Listener {
@Inject
private ListenerService listenerService;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
if (ListenerService.shouldCancelEvent(event)) { if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }

View File

@ -1,26 +0,0 @@
package fr.xephi.authme.listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.spigotmc.event.player.PlayerSpawnLocationEvent;
import fr.xephi.authme.AuthMe;
/**
* Listener of player events for events introduced in Minecraft 1.9.
*/
public class AuthMePlayerListener19 implements Listener {
private final AuthMe plugin;
public AuthMePlayerListener19(AuthMe plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerSpawn(PlayerSpawnLocationEvent event) {
event.setSpawnLocation(plugin.getSpawnLocation(event.getPlayer()));
}
}

View File

@ -5,6 +5,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.settings.properties.ProtectionSettings;
@ -16,26 +17,26 @@ import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.event.server.ServerListPingEvent;
import javax.inject.Inject;
/** /**
*/ */
public class AuthMeServerListener implements Listener { public class AuthMeServerListener implements Listener {
private final AuthMe plugin; @Inject
private final Messages messages; private AuthMe plugin;
private final NewSetting settings; @Inject
private final PluginHooks pluginHooks; private Messages messages;
private final SpawnLoader spawnLoader; @Inject
private final ValidationService validationService; private NewSetting settings;
@Inject
public AuthMeServerListener(AuthMe plugin, Messages messages, NewSetting settings, PluginHooks pluginHooks, private PluginHooks pluginHooks;
SpawnLoader spawnLoader, ValidationService validationService) { @Inject
this.plugin = plugin; private SpawnLoader spawnLoader;
this.messages = messages; @Inject
this.settings = settings; private ValidationService validationService;
this.pluginHooks = pluginHooks; @Inject
this.spawnLoader = spawnLoader; private PermissionsManager permissionsManager;
this.validationService = validationService;
}
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onServerPing(ServerListPingEvent event) { public void onServerPing(ServerListPingEvent event) {
@ -54,10 +55,11 @@ public class AuthMeServerListener implements Listener {
return; return;
} }
// Call the onPluginDisable method in the permissions manager
plugin.getPermissionsManager().onPluginDisable(event);
final String pluginName = event.getPlugin().getName(); final String pluginName = event.getPlugin().getName();
// Call the onPluginDisable method in the permissions manager
permissionsManager.onPluginDisable(pluginName);
if ("Essentials".equalsIgnoreCase(pluginName)) { if ("Essentials".equalsIgnoreCase(pluginName)) {
pluginHooks.unhookEssentials(); pluginHooks.unhookEssentials();
ConsoleLogger.info("Essentials has been disabled: unhooking"); ConsoleLogger.info("Essentials has been disabled: unhooking");
@ -87,10 +89,11 @@ public class AuthMeServerListener implements Listener {
return; return;
} }
// Call the onPluginEnable method in the permissions manager
plugin.getPermissionsManager().onPluginEnable(event);
final String pluginName = event.getPlugin().getName(); final String pluginName = event.getPlugin().getName();
// Call the onPluginEnable method in the permissions manager
permissionsManager.onPluginEnable(pluginName);
if ("Essentials".equalsIgnoreCase(pluginName)) { if ("Essentials".equalsIgnoreCase(pluginName)) {
pluginHooks.tryHookToEssentials(); pluginHooks.tryHookToEssentials();
} else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) {

View File

@ -11,8 +11,11 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import javax.inject.Inject;
public class AuthMeTabCompletePacketAdapter extends PacketAdapter { public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
@Inject
public AuthMeTabCompletePacketAdapter(AuthMe plugin) { public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE); super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
} }

View File

@ -14,14 +14,13 @@ import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedGameProfile;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.BukkitService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Arrays; import java.util.Arrays;
import java.util.logging.Level; import java.util.logging.Level;
@ -30,6 +29,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter {
private final BukkitService bukkitService; private final BukkitService bukkitService;
@Inject
public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) { public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO); super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
this.bukkitService = bukkitService; this.bukkitService = bukkitService;

View File

@ -0,0 +1,33 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.StringUtils;
/**
* Exception thrown when a verification has failed.
*/
@SuppressWarnings("serial")
public class FailedVerificationException extends Exception {
private final MessageKey reason;
private final String[] args;
public FailedVerificationException(MessageKey reason, String... args) {
this.reason = reason;
this.args = args;
}
public MessageKey getReason() {
return reason;
}
public String[] getArgs() {
return args;
}
@Override
public String toString() {
return getClass().getSimpleName() + ": reason=" + (reason == null ? "null" : reason)
+ ";args=" + (args == null ? "null" : StringUtils.join(", ", args));
}
}

View File

@ -1,26 +1,48 @@
package fr.xephi.authme.listener; package fr.xephi.authme.listener;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityEvent; import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.player.PlayerEvent; import org.bukkit.event.player.PlayerEvent;
/** import javax.inject.Inject;
* Service class for the AuthMe listeners. import java.util.HashSet;
*/ import java.util.Set;
final class ListenerService {
private ListenerService() { /**
* Service class for the AuthMe listeners to determine whether an event should be canceled.
*/
class ListenerService implements SettingsDependent {
private final DataSource dataSource;
private final PluginHooks pluginHooks;
private final PlayerCache playerCache;
private boolean isRegistrationForced;
private Set<String> unrestrictedNames;
@Inject
ListenerService(NewSetting settings, DataSource dataSource, PluginHooks pluginHooks, PlayerCache playerCache) {
this.dataSource = dataSource;
this.pluginHooks = pluginHooks;
this.playerCache = playerCache;
loadSettings(settings);
} }
/** /**
* Return whether an event should be canceled (for unauthenticated, non-NPC players). * Returns whether an event should be canceled (for unauthenticated, non-NPC players).
* *
* @param event The event to process * @param event the event to process
* @return True if the event should be canceled, false otherwise * @return true if the event should be canceled, false otherwise
*/ */
public static boolean shouldCancelEvent(EntityEvent event) { public boolean shouldCancelEvent(EntityEvent event) {
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if (entity == null || !(entity instanceof Player)) { if (entity == null || !(entity instanceof Player)) {
return false; return false;
@ -31,24 +53,57 @@ final class ListenerService {
} }
/** /**
* Return whether an event should be canceled (for unauthenticated, non-NPC players). * Returns whether an event should be canceled (for unauthenticated, non-NPC players).
* *
* @param event The event to process * @param event the event to process
* @return True if the event should be canceled, false otherwise * @return true if the event should be canceled, false otherwise
*/ */
public static boolean shouldCancelEvent(PlayerEvent event) { public boolean shouldCancelEvent(PlayerEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
return shouldCancelEvent(player); return shouldCancelEvent(player);
} }
/** /**
* Return, based on the player associated with the event, whether or not the event should be canceled. * Returns, based on the player associated with the event, whether or not the event should be canceled.
* *
* @param player The player to verify * @param player the player to verify
* @return True if the associated event should be canceled, false otherwise * @return true if the associated event should be canceled, false otherwise
*/ */
public static boolean shouldCancelEvent(Player player) { public boolean shouldCancelEvent(Player player) {
return player != null && !Utils.checkAuth(player) && !Utils.isNPC(player); return player != null && !checkAuth(player.getName()) && !pluginHooks.isNpc(player);
} }
@Override
public void loadSettings(NewSetting settings) {
isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE);
// Keep unrestricted names as Set for more efficient contains()
unrestrictedNames = new HashSet<>(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES));
}
/**
* Checks whether the player is allowed to perform actions (i.e. whether he is logged in
* or if other settings permit playing).
*
* @param name the name of the player to verify
* @return true if the player may play, false otherwise
*/
private boolean checkAuth(String name) {
if (isUnrestricted(name) || playerCache.isAuthenticated(name)) {
return true;
}
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
return true;
}
return false;
}
/**
* Checks if the name is unrestricted according to the configured settings.
*
* @param name the name to verify
* @return true if unrestricted, false otherwise
*/
private boolean isUnrestricted(String name) {
return unrestrictedNames.contains(name.toLowerCase());
}
} }

Some files were not shown because too many files have changed in this diff Show More