diff --git a/build.gradle.kts b/build.gradle.kts index abd38eab..95e26740 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,189 +1,50 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { `java-library` `maven-publish` + kotlin("jvm") version "2.0.0" id("com.github.johnrengelman.shadow") version "8.1.1" } -description = "Fork of the first authentication plugin for the Bukkit API!" +subprojects { -java { - withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_1_8 -} + // Apply Plugins + apply(plugin = "java-library") + apply(plugin = "maven-publish") + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "com.github.johnrengelman.shadow") -tasks.withType { - options.encoding = "UTF-8" -} + // Java Settings + java { + withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } -repositories { - mavenCentral() - mavenLocal() - // PaperMC - maven("https://papermc.io/repo/repository/maven-public/") - maven("https://repo.opencollab.dev/main/") - maven("https://repo.opencollab.dev/maven-snapshots/") - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") - maven("https://repository.apache.org/content/repositories/snapshots/") - maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") - maven("https://repo.codemc.io/repository/maven-public/") - maven("https://repo.essentialsx.net/releases/") - maven("https://repo.dmulloy2.net/nexus/repository/releases/") - maven("https://repo.dmulloy2.net/nexus/repository/snapshots/") - maven("https://repo.onarandombox.com/content/repositories/multiverse/") - maven("https://repo.onarandombox.com/content/repositories/multiverse-snapshots/") - maven("https://nexuslite.gcnt.net/repos/other/") - maven("https://jitpack.io/") - maven("https://repo.maven.apache.org/maven2/") -} + tasks.withType { + options.encoding = "UTF-8" + } -dependencies { - // Spigot API, https://www.spigotmc.org/ - compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") - // Java Libraries - compileOnly("org.geysermc.floodgate:api:2.2.2-SNAPSHOT") - // Jalu Injector - implementation("ch.jalu:injector:1.0") - // String comparison library. Used for dynamic help system. - implementation("net.ricecode:string-similarity:1.0.0") - // MaxMind GEO IP with our modifications to use GSON in replacement of the big Jackson dependency - // GSON is already included and therefore it reduces the file size in comparison to the original version - implementation("com.maxmind.db:maxmind-db-gson:2.0.3") { - exclude("com.google.code.gson", "gson") - } - // Library for tar archives - implementation("javatar:javatar:2.5") - // Java Email Library - implementation("org.apache.commons:commons-email:1.6-SNAPSHOT") - // Log4J Logger (required by the console filter) - compileOnly("org.apache.logging.log4j:log4j-core:2.20.0") // Log4J version bundled in 1.12.2 - // Libby - implementation("com.alessiodp.libby:libby-bukkit:2.0.0-SNAPSHOT") - // Database Connection Pool - implementation("com.zaxxer:HikariCP:4.0.3" /* Latest java 8 release */) { - exclude("org.slf4j", "slf4j-api") - } - // HikariCP Logger - implementation("org.slf4j:slf4j-simple:1.7.36") // We can't update to 2.x as long as we use HikariCP for java 8 - // PBKDF2 implementation - implementation("de.rtner:PBKDF2:1.1.4") - // MySQL connector, shaded into the legacy jar - implementation("com.mysql:mysql-connector-j:8.4.0") - implementation("org.mariadb.jdbc:mariadb-java-client:3.3.3") - // Argon2 implementation - implementation("de.mkammerer:argon2-jvm-nolibs:2.11") - // TOTP client - implementation("com.warrenstrange:googleauth:1.5.0") - // Keep in sync with spigot 1.19 - implementation("com.google.guava:guava:33.2.1-jre") { - exclude("org.checkerframework", "checker-qual") - } - implementation("com.google.code.gson:gson:2.10.1") - // ConfigMe - implementation("ch.jalu:configme:1.3.1") { - exclude("org.yaml", "snakeyaml") - } - // bStats metrics - implementation("org.bstats:bstats-bukkit:3.0.2") - // ProtocolLib - compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0") - // Adventure API - implementation("net.kyori:adventure-text-minimessage:4.17.0") - implementation("net.kyori:adventure-platform-bukkit:4.3.2") - implementation("net.kyori:adventure-text-serializer-gson:4.17.0") - // LuckPerms plugin - compileOnly("net.luckperms:api:5.4") - // PermissionsEx plugin - compileOnly("ru.tehkode:PermissionsEx:1.23.5-SNAPSHOT") - // Dependencies used by HAProxy feature -// implementation("io.netty:netty-codec-haproxy:4.1.104.Final") -// compileOnly("commons-validator:commons-validator:1.8.0") - // zPermissions plugin - compileOnly("org.tyrannyofheaven.bukkit:zPermissions:1.4.3-SNAPSHOT") { - exclude("org.avaje", "ebean") - } - // Vault, https://dev.bukkit.org/bukkit-plugins/vault/ - compileOnly("net.milkbowl.vault:VaultAPI:1.7") - // Multi World plugin, https://www.spigotmc.org/resources/multiverse-core.390/ - compileOnly("com.onarandombox.multiversecore:Multiverse-Core:4.3.1") - // EssentialsX plugin - compileOnly("net.essentialsx:EssentialsX:2.20.1") - // BCrypt implementation - implementation("at.favre.lib:bcrypt:0.10.2") - // XAuth, another authentication plugin, required by the database converter - compileOnly("de.luricos.bukkit:xAuth:2.6.1-SNAPSHOT") - implementation("ch.jalu:datasourcecolumns:0.1.1-SNAPSHOT") - implementation("org.postgresql:postgresql:42.7.3") { - exclude("org.checkerframework", "checker-qual") - } - // Required to mock the LuckPerms API - testImplementation("org.checkerframework:checker-qual:3.40.0") - // Universal Scheduler - implementation("com.github.Anon8281:UniversalScheduler:0.1.6") - // JDBC drivers for datasource integration tests - testImplementation("org.xerial:sqlite-jdbc:3.46.0.0") - compileOnly("com.h2database:h2:2.2.224") -} - -tasks { - build { dependsOn(shadowJar) } - // ShadowJar Config - shadowJar { - // Options - archiveAppendix.set("") - archiveClassifier.set("") - archiveBaseName.set("AuthMe") - destinationDirectory.set(file("$rootDir/outs")) - // Libraries Relocate - relocate("org.apache.http", "fr.xephi.authme.libs.org.apache.http") - relocate("org.apache.commons", "fr.xephi.authme.libs.org.apache.commons") - relocate("waffle", "fr.xephi.authme.libs.waffle") - relocate("com.github.benmanes.caffeine", "fr.xephi.authme.libs.com.github.benmanes.caffeine") - relocate("com.google.common", "fr.xephi.authme.libs.com.google.common") - relocate("com.google.thirdparty", "fr.xephi.authme.libs.com.google.thirdparty") - relocate("com.google.j2objc", "fr.xephi.authme.libs.com.google.j2objc") - relocate("com.google.errorprone", "fr.xephi.authme.libs.com.google.errorprone") - relocate("com.google.gson", "fr.xephi.authme.libs.com.google.gson") - relocate("org.apache.http", "fr.xephi.authme.libs.org.apache.http") - relocate("org.apache.commons", "fr.xephi.authme.libs.org.apache.commons") - relocate("waffle", "fr.xephi.authme.libs.waffle") - relocate("com.github.benmanes.caffeine", "fr.xephi.authme.libs.com.github.benmanes.caffeine") - relocate("ch.jalu", "fr.xephi.authme.libs.ch.jalu") - relocate("com.zaxxer.hikari", "fr.xephi.authme.libs.com.zaxxer.hikari") - relocate("org.slf4j", "fr.xephi.authme.libs.org.slf4j") - relocate("com.maxmind.db", "fr.xephi.authme.libs.com.maxmind.db") - relocate("com.ice.tar", "fr.xephi.authme.libs.com.icetar.tar") - relocate("net.ricecode.similarity", "fr.xephi.authme.libs.ricecode.net.ricecode.similarity") - relocate("de.rtner", "fr.xephi.authme.libs.de.rtner") - relocate("org.picketbox", "fr.xephi.authme.libs.org.picketbox") - relocate("org.jboss.crypto", "fr.xephi.authme.libs.org.jboss.crypto") - relocate("org.jboss.security", "fr.xephi.authme.libs.org.jboss.security") - relocate("de.mkammerer", "fr.xephi.authme.libs.de.mkammerer") - relocate("com.warrenstrange", "fr.xephi.authme.libs.com.warrenstrange") - relocate("javax.inject", "fr.xephi.authme.libs.javax.inject") - relocate("at.favre.lib", "fr.xephi.authme.libs.at.favre.lib") - relocate("org.postgresql", "fr.xephi.authme.libs.org.postgresql") - // bStats metrics class - relocate("org.bstats", "fr.xephi.authme.libs.org.bstats") - relocate("org.mariadb.jdbc", "fr.xephi.authme.libs.org.mariadb.jdbc") - relocate( - "com.github.Anon8281.universalScheduler", - "fr.xephi.authme.libs.com.github.Anon8281.universalScheduler" - ) - relocate("com.mysql", "fr.xephi.authme.libs.com.mysql") - relocate("com.google.protobuf", "fr.xephi.authme.libs.com.google.protobuf") - relocate("io.netty", "fr.xephi.authme.libs.io.netty") - relocate("org.apache.commons.validator", "fr.xephi.authme.libs.org.apache.commons.validator") - relocate("com.alessiodp.libby", "fr.xephi.authme.libs.com.alessiodp.libby") - relocate("net.kyori.adventure", "fr.xephi.authme.libs.net.kyori.adventure") - relocate("net.kyori.examination", "fr.xephi.authme.libs.net.kyori.examination") - relocate("net.kyori.option", "fr.xephi.authme.libs.net.kyori.option") - } -} - -publishing { - publications { - create("maven") { - from(components["java"]) + // Kotlin Settings + kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 } } -} + + // Common Repositories + repositories { + mavenCentral() + mavenLocal() + } + + publishing { + publications { + create("maven") { + from(components["java"]) + } + } + } + +} \ No newline at end of file diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts new file mode 100644 index 00000000..dc6edf87 --- /dev/null +++ b/plugin/build.gradle.kts @@ -0,0 +1,166 @@ +subprojects { + + repositories { + // PaperMC + maven("https://papermc.io/repo/repository/maven-public/") + maven("https://repo.opencollab.dev/main/") + maven("https://repo.opencollab.dev/maven-snapshots/") + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + maven("https://repository.apache.org/content/repositories/snapshots/") + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") + maven("https://repo.codemc.io/repository/maven-public/") + maven("https://repo.essentialsx.net/releases/") + maven("https://repo.dmulloy2.net/nexus/repository/releases/") + maven("https://repo.dmulloy2.net/nexus/repository/snapshots/") + maven("https://repo.onarandombox.com/content/repositories/multiverse/") + maven("https://repo.onarandombox.com/content/repositories/multiverse-snapshots/") + maven("https://nexuslite.gcnt.net/repos/other/") + maven("https://jitpack.io/") + maven("https://repo.maven.apache.org/maven2/") + } + + dependencies { + // Spigot API, https://www.spigotmc.org/ + compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") + // Java Libraries + compileOnly("org.geysermc.floodgate:api:2.2.2-SNAPSHOT") + // Jalu Injector + implementation("ch.jalu:injector:1.0") + // String comparison library. Used for dynamic help system. + implementation("net.ricecode:string-similarity:1.0.0") + // MaxMind GEO IP with our modifications to use GSON in replacement of the big Jackson dependency + // GSON is already included and therefore it reduces the file size in comparison to the original version + implementation("com.maxmind.db:maxmind-db-gson:2.0.3") { + exclude("com.google.code.gson", "gson") + } + // Library for tar archives + implementation("javatar:javatar:2.5") + // Java Email Library + implementation("org.apache.commons:commons-email:1.6-SNAPSHOT") + // Log4J Logger (required by the console filter) + compileOnly("org.apache.logging.log4j:log4j-core:2.20.0") // Log4J version bundled in 1.12.2 + // Libby + implementation("com.alessiodp.libby:libby-bukkit:2.0.0-SNAPSHOT") + // Database Connection Pool + implementation("com.zaxxer:HikariCP:4.0.3" /* Latest java 8 release */) { + exclude("org.slf4j", "slf4j-api") + } + // HikariCP Logger + implementation("org.slf4j:slf4j-simple:1.7.36") // We can't update to 2.x as long as we use HikariCP for java 8 + // PBKDF2 implementation + implementation("de.rtner:PBKDF2:1.1.4") + // MySQL connector, shaded into the legacy jar + implementation("com.mysql:mysql-connector-j:8.4.0") + implementation("org.mariadb.jdbc:mariadb-java-client:3.3.3") + // Argon2 implementation + implementation("de.mkammerer:argon2-jvm-nolibs:2.11") + // TOTP client + implementation("com.warrenstrange:googleauth:1.5.0") + // Keep in sync with spigot 1.19 + implementation("com.google.guava:guava:33.2.1-jre") { + exclude("org.checkerframework", "checker-qual") + } + implementation("com.google.code.gson:gson:2.10.1") + // ConfigMe + implementation("ch.jalu:configme:1.3.1") { + exclude("org.yaml", "snakeyaml") + } + // bStats metrics + implementation("org.bstats:bstats-bukkit:3.0.2") + // ProtocolLib + compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0") + // Adventure API + implementation("net.kyori:adventure-text-minimessage:4.17.0") + implementation("net.kyori:adventure-platform-bukkit:4.3.2") + implementation("net.kyori:adventure-text-serializer-gson:4.17.0") + // LuckPerms plugin + compileOnly("net.luckperms:api:5.4") + // PermissionsEx plugin + compileOnly("ru.tehkode:PermissionsEx:1.23.5-SNAPSHOT") + // Dependencies used by HAProxy feature +// implementation("io.netty:netty-codec-haproxy:4.1.104.Final") +// compileOnly("commons-validator:commons-validator:1.8.0") + // zPermissions plugin + compileOnly("org.tyrannyofheaven.bukkit:zPermissions:1.4.3-SNAPSHOT") { + exclude("org.avaje", "ebean") + } + // Vault, https://dev.bukkit.org/bukkit-plugins/vault/ + compileOnly("net.milkbowl.vault:VaultAPI:1.7") + // Multi World plugin, https://www.spigotmc.org/resources/multiverse-core.390/ + compileOnly("com.onarandombox.multiversecore:Multiverse-Core:4.3.1") + // EssentialsX plugin + compileOnly("net.essentialsx:EssentialsX:2.20.1") + // BCrypt implementation + implementation("at.favre.lib:bcrypt:0.10.2") + // XAuth, another authentication plugin, required by the database converter + compileOnly("de.luricos.bukkit:xAuth:2.6.1-SNAPSHOT") + implementation("ch.jalu:datasourcecolumns:0.1.1-SNAPSHOT") + implementation("org.postgresql:postgresql:42.7.3") { + exclude("org.checkerframework", "checker-qual") + } + // Required to mock the LuckPerms API + testImplementation("org.checkerframework:checker-qual:3.40.0") + // Universal Scheduler + implementation("com.github.Anon8281:UniversalScheduler:0.1.6") + // JDBC drivers for datasource integration tests + testImplementation("org.xerial:sqlite-jdbc:3.46.0.0") + compileOnly("com.h2database:h2:2.2.224") + } + + tasks { + build { dependsOn(shadowJar) } + // ShadowJar Config + shadowJar { + // Options + archiveAppendix.set("") + archiveClassifier.set("") + archiveBaseName.set("AuthMe") + destinationDirectory.set(file("$rootDir/outs")) + // Libraries Relocate + relocate("org.apache.http", "fr.xephi.authme.libs.org.apache.http") + relocate("org.apache.commons", "fr.xephi.authme.libs.org.apache.commons") + relocate("waffle", "fr.xephi.authme.libs.waffle") + relocate("com.github.benmanes.caffeine", "fr.xephi.authme.libs.com.github.benmanes.caffeine") + relocate("com.google.common", "fr.xephi.authme.libs.com.google.common") + relocate("com.google.thirdparty", "fr.xephi.authme.libs.com.google.thirdparty") + relocate("com.google.j2objc", "fr.xephi.authme.libs.com.google.j2objc") + relocate("com.google.errorprone", "fr.xephi.authme.libs.com.google.errorprone") + relocate("com.google.gson", "fr.xephi.authme.libs.com.google.gson") + relocate("org.apache.http", "fr.xephi.authme.libs.org.apache.http") + relocate("org.apache.commons", "fr.xephi.authme.libs.org.apache.commons") + relocate("waffle", "fr.xephi.authme.libs.waffle") + relocate("com.github.benmanes.caffeine", "fr.xephi.authme.libs.com.github.benmanes.caffeine") + relocate("ch.jalu", "fr.xephi.authme.libs.ch.jalu") + relocate("com.zaxxer.hikari", "fr.xephi.authme.libs.com.zaxxer.hikari") + relocate("org.slf4j", "fr.xephi.authme.libs.org.slf4j") + relocate("com.maxmind.db", "fr.xephi.authme.libs.com.maxmind.db") + relocate("com.ice.tar", "fr.xephi.authme.libs.com.icetar.tar") + relocate("net.ricecode.similarity", "fr.xephi.authme.libs.ricecode.net.ricecode.similarity") + relocate("de.rtner", "fr.xephi.authme.libs.de.rtner") + relocate("org.picketbox", "fr.xephi.authme.libs.org.picketbox") + relocate("org.jboss.crypto", "fr.xephi.authme.libs.org.jboss.crypto") + relocate("org.jboss.security", "fr.xephi.authme.libs.org.jboss.security") + relocate("de.mkammerer", "fr.xephi.authme.libs.de.mkammerer") + relocate("com.warrenstrange", "fr.xephi.authme.libs.com.warrenstrange") + relocate("javax.inject", "fr.xephi.authme.libs.javax.inject") + relocate("at.favre.lib", "fr.xephi.authme.libs.at.favre.lib") + relocate("org.postgresql", "fr.xephi.authme.libs.org.postgresql") + // bStats metrics class + relocate("org.bstats", "fr.xephi.authme.libs.org.bstats") + relocate("org.mariadb.jdbc", "fr.xephi.authme.libs.org.mariadb.jdbc") + relocate( + "com.github.Anon8281.universalScheduler", + "fr.xephi.authme.libs.com.github.Anon8281.universalScheduler" + ) + relocate("com.mysql", "fr.xephi.authme.libs.com.mysql") + relocate("com.google.protobuf", "fr.xephi.authme.libs.com.google.protobuf") + relocate("io.netty", "fr.xephi.authme.libs.io.netty") + relocate("org.apache.commons.validator", "fr.xephi.authme.libs.org.apache.commons.validator") + relocate("com.alessiodp.libby", "fr.xephi.authme.libs.com.alessiodp.libby") + relocate("net.kyori.adventure", "fr.xephi.authme.libs.net.kyori.adventure") + relocate("net.kyori.examination", "fr.xephi.authme.libs.net.kyori.examination") + relocate("net.kyori.option", "fr.xephi.authme.libs.net.kyori.option") + } + } + +} diff --git a/project/build.gradle.kts b/project/build.gradle.kts new file mode 100644 index 00000000..2a6624a7 --- /dev/null +++ b/project/build.gradle.kts @@ -0,0 +1,9 @@ + +description = "Fork of the first authentication plugin for the Bukkit API!" + +repositories { + mavenCentral() +} + +dependencies { +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bfc72a3c..04ea9300 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,10 @@ rootProject.name = "authme" + +applyAll("project") +applyAll("plugin") + +fun applyAll(name: String) { + File(rootDir, name).listFiles()?.filter { it.isDirectory }?.forEach { + include("$name:${it.name}") + } +} \ No newline at end of file diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java deleted file mode 100644 index f2bff2dd..00000000 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ /dev/null @@ -1,474 +0,0 @@ -package fr.xephi.authme; - -import ch.jalu.injector.Injector; -import ch.jalu.injector.InjectorBuilder; -import com.alessiodp.libby.BukkitLibraryManager; -import com.github.Anon8281.universalScheduler.UniversalScheduler; -import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; -import fr.xephi.authme.api.v3.AuthMeApi; -import fr.xephi.authme.command.CommandHandler; -import fr.xephi.authme.command.TabCompleteHandler; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.DataSourceProvider; -import fr.xephi.authme.initialization.OnShutdownPlayerSaver; -import fr.xephi.authme.initialization.OnStartupTasks; -import fr.xephi.authme.initialization.SettingsProvider; -import fr.xephi.authme.initialization.TaskCloser; -import fr.xephi.authme.listener.AdvancedShulkerFixListener; -import fr.xephi.authme.listener.BedrockAutoLoginListener; -import fr.xephi.authme.listener.BlockListener; -import fr.xephi.authme.listener.DoubleLoginFixListener; -import fr.xephi.authme.listener.EntityListener; -import fr.xephi.authme.listener.LoginLocationFixListener; -import fr.xephi.authme.listener.PlayerListener; -import fr.xephi.authme.listener.PlayerListener111; -import fr.xephi.authme.listener.PlayerListener19; -import fr.xephi.authme.listener.PlayerListener19Spigot; -import fr.xephi.authme.listener.PlayerListenerHigherThan18; -import fr.xephi.authme.listener.PurgeListener; -import fr.xephi.authme.listener.ServerListener; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.Sha256; -import fr.xephi.authme.service.BackupService; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.MigrationService; -import fr.xephi.authme.service.bungeecord.BungeeReceiver; -import fr.xephi.authme.service.velocity.VelocityReceiver; -import fr.xephi.authme.service.yaml.YamlParseException; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SettingsWarner; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.task.CleanupTask; -import fr.xephi.authme.task.Updater; -import fr.xephi.authme.task.purge.PurgeService; -import fr.xephi.authme.util.ExceptionUtils; -import org.bukkit.Server; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.NotNull; - -import javax.inject.Inject; -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Objects; -import java.util.function.Consumer; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE; -import static fr.xephi.authme.util.Utils.isClassLoaded; - -/** - * The AuthMe main class. - */ -public class AuthMe extends JavaPlugin { - - // Constants - private static final String PLUGIN_NAME = "AuthMeReloaded"; - private static final String LOG_FILENAME = "authme.log"; - private static final int CLEANUP_INTERVAL = 5 * TICKS_PER_MINUTE; - - // Version and build number values - private static String pluginVersion = "5.7.0-Fork"; - private static final String pluginBuild = "b"; - private static String pluginBuildNumber = "51"; - // Private instances - private EmailService emailService; - private CommandHandler commandHandler; - private static TaskScheduler scheduler; - @Inject - public static Settings settings; - private DataSource database; - private BukkitService bukkitService; - private Injector injector; - private BackupService backupService; - public static ConsoleLogger logger; - - /** - * Constructor. - */ - public AuthMe() { - } - - /** - * Get the plugin's build - * - * @return The plugin's build - */ - public static String getPluginBuild() { - return pluginBuild; - } - - - /** - * Get the plugin's name. - * - * @return The plugin's name. - */ - public static String getPluginName() { - return PLUGIN_NAME; - } - - /** - * Get the plugin's version. - * - * @return The plugin's version. - */ - public static String getPluginVersion() { - return pluginVersion; - } - - /** - * Get the plugin's build number. - * - * @return The plugin's build number. - */ - public static String getPluginBuildNumber() { - return pluginBuildNumber; - } - - /** - * Get the scheduler - */ - public static TaskScheduler getScheduler() { - return scheduler; - } - - /** - * The library manager - */ - public static BukkitLibraryManager libraryManager; - - /** - * Method called when the server enables the plugin. - */ - @Override - public void onEnable() { - // Load the plugin version data from the plugin description file - loadPluginInfo(getDescription().getVersion()); - scheduler = UniversalScheduler.getScheduler(this); - libraryManager = new BukkitLibraryManager(this); - - // Set the Logger instance and log file path - ConsoleLogger.initialize(getLogger(), new File(getDataFolder(), LOG_FILENAME)); - logger = ConsoleLoggerFactory.get(AuthMe.class); - logger.info("You are running an unofficial fork version of AuthMe!"); - - - // Check server version - if (!isClassLoaded("org.spigotmc.event.player.PlayerSpawnLocationEvent") - || !isClassLoaded("org.bukkit.event.player.PlayerInteractAtEntityEvent")) { - logger.warning("You are running an unsupported server version (" + getServerNameVersionSafe() + "). " - + "AuthMe requires Spigot 1.8.X or later!"); - stopOrUnload(); - return; - } - - // Prevent running AuthMeBridge due to major exploit issues - if (getServer().getPluginManager().isPluginEnabled("AuthMeBridge")) { - logger.warning("Detected AuthMeBridge, support for it has been dropped as it was " - + "causing exploit issues, please use AuthMeBungee instead! Aborting!"); - stopOrUnload(); - return; - } - - // Initialize the plugin - try { - initialize(); - } catch (Throwable th) { - YamlParseException yamlParseException = ExceptionUtils.findThrowableInCause(YamlParseException.class, th); - if (yamlParseException == null) { - logger.logException("Aborting initialization of AuthMe:", th); - th.printStackTrace(); - } else { - logger.logException("File '" + yamlParseException.getFile() + "' contains invalid YAML. " - + "Please run its contents through http://yamllint.com", yamlParseException); - } - stopOrUnload(); - return; - } - - // Show settings warnings - injector.getSingleton(SettingsWarner.class).logWarningsForMisconfigurations(); - - // Schedule clean up task - CleanupTask cleanupTask = injector.getSingleton(CleanupTask.class); - cleanupTask.runTaskTimerAsynchronously(this, CLEANUP_INTERVAL, CLEANUP_INTERVAL); - // Do a backup on start - backupService.doBackup(BackupService.BackupCause.START); - // Set up Metrics - OnStartupTasks.sendMetrics(this, settings); - if (settings.getProperty(SecuritySettings.SHOW_STARTUP_BANNER)) { - logger.info("\n" + " ___ __ __ __ ___ \n" + - " / | __ __/ /_/ /_ / |/ /__ \n" + - " / /| |/ / / / __/ __ \\/ /|_/ / _ \\\n" + - " / ___ / /_/ / /_/ / / / / / / __/\n" + - "/_/ |_\\__,_/\\__/_/ /_/_/ /_/\\___/ \n" + - " "); - } - //detect server brand with classloader - checkServerType(); - try { - Objects.requireNonNull(getCommand("register")).setTabCompleter(new TabCompleteHandler()); - Objects.requireNonNull(getCommand("login")).setTabCompleter(new TabCompleteHandler()); - } catch (NullPointerException ignored) { - } - logger.info("AuthMeReReloaded is enabled successfully!"); - // Purge on start if enabled - PurgeService purgeService = injector.getSingleton(PurgeService.class); - purgeService.runAutoPurge(); - logger.info("GitHub: https://github.com/HaHaWTH/AuthMeReReloaded/"); - if (settings.getProperty(SecuritySettings.CHECK_FOR_UPDATES)) { - checkForUpdates(); - } - } - - - /** - * Load the version and build number of the plugin from the description file. - * - * @param versionRaw the version as given by the plugin description file - */ - - private static void loadPluginInfo(String versionRaw) { - int index = versionRaw.lastIndexOf("-"); - if (index != -1) { - pluginVersion = versionRaw.substring(0, index); - pluginBuildNumber = versionRaw.substring(index + 1); - if (pluginBuildNumber.startsWith("b")) { - pluginBuildNumber = pluginBuildNumber.substring(1); - } - } - } - - /** - * Initialize the plugin and all the services. - */ - private void initialize() { - // Create plugin folder - getDataFolder().mkdir(); - - // Create injector, provide elements from the Bukkit environment and register providers - injector = new InjectorBuilder() - .addDefaultHandlers("fr.xephi.authme") - .create(); - injector.register(AuthMe.class, this); - injector.register(Server.class, getServer()); - injector.register(PluginManager.class, getServer().getPluginManager()); - injector.provide(DataFolder.class, getDataFolder()); - injector.registerProvider(Settings.class, SettingsProvider.class); - injector.registerProvider(DataSource.class, DataSourceProvider.class); - - // Get settings and set up logger - settings = injector.getSingleton(Settings.class); - ConsoleLoggerFactory.reloadSettings(settings); - OnStartupTasks.setupConsoleFilter(getLogger()); - - // Set all service fields on the AuthMe class - instantiateServices(injector); - - // Convert deprecated PLAINTEXT hash entries - MigrationService.changePlainTextToSha256(settings, database, new Sha256()); - - // If the server is empty (fresh start) just set all the players as unlogged - if (bukkitService.getOnlinePlayers().isEmpty()) { - database.purgeLogged(); - } - - // Register event listeners - registerEventListeners(injector); - - // Start Email recall task if needed - OnStartupTasks onStartupTasks = injector.newInstance(OnStartupTasks.class); - onStartupTasks.scheduleRecallEmailTask(); - } - - /** - * Instantiates all services. - * - * @param injector the injector - */ - void instantiateServices(Injector injector) { - database = injector.getSingleton(DataSource.class); - bukkitService = injector.getSingleton(BukkitService.class); - commandHandler = injector.getSingleton(CommandHandler.class); - emailService = injector.getSingleton(EmailService.class); - backupService = injector.getSingleton(BackupService.class); - - // Trigger instantiation (class not used elsewhere) - injector.getSingleton(BungeeReceiver.class); - injector.getSingleton(VelocityReceiver.class); - - // Trigger construction of API classes; they will keep track of the singleton - injector.getSingleton(AuthMeApi.class); - } - - /** - * Registers all event listeners. - * - * @param injector the injector - */ - void registerEventListeners(Injector injector) { - // Get the plugin manager instance - PluginManager pluginManager = getServer().getPluginManager(); - - // Register event listeners - pluginManager.registerEvents(injector.getSingleton(PlayerListener.class), this); - pluginManager.registerEvents(injector.getSingleton(BlockListener.class), this); - pluginManager.registerEvents(injector.getSingleton(EntityListener.class), this); - pluginManager.registerEvents(injector.getSingleton(ServerListener.class), this); - - - // Try to register 1.8+ player listeners - if (isClassLoaded("org.bukkit.event.entity.EntityPickupItemEvent") && isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) { - pluginManager.registerEvents(injector.getSingleton(PlayerListenerHigherThan18.class), this); - } else if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) { - pluginManager.registerEvents(injector.getSingleton(PlayerListener19.class), this); - } -// Try to register 1.9 player listeners(Moved to else-if) -// if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) { -// pluginManager.registerEvents(injector.getSingleton(PlayerListener19.class), this); -// } - - // Try to register 1.9 spigot player listeners - if (isClassLoaded("org.spigotmc.event.player.PlayerSpawnLocationEvent")) { - pluginManager.registerEvents(injector.getSingleton(PlayerListener19Spigot.class), this); - } - - // Register listener for 1.11 events if available - if (isClassLoaded("org.bukkit.event.entity.EntityAirChangeEvent")) { - pluginManager.registerEvents(injector.getSingleton(PlayerListener111.class), this); - } - - //Register 3rd party listeners - if (settings.getProperty(SecuritySettings.FORCE_LOGIN_BEDROCK) && settings.getProperty(HooksSettings.HOOK_FLOODGATE_PLAYER) && getServer().getPluginManager().getPlugin("floodgate") != null) { - pluginManager.registerEvents(injector.getSingleton(BedrockAutoLoginListener.class), this); - } else if (settings.getProperty(SecuritySettings.FORCE_LOGIN_BEDROCK) && (!settings.getProperty(HooksSettings.HOOK_FLOODGATE_PLAYER) || getServer().getPluginManager().getPlugin("floodgate") == null)) { - logger.warning("Failed to enable BedrockAutoLogin, ensure hookFloodgate: true and floodgate is loaded."); - } - if (settings.getProperty(SecuritySettings.LOGIN_LOC_FIX_SUB_UNDERGROUND) || settings.getProperty(SecuritySettings.LOGIN_LOC_FIX_SUB_PORTAL)) { - pluginManager.registerEvents(injector.getSingleton(LoginLocationFixListener.class), this); - } - if (settings.getProperty(SecuritySettings.ANTI_GHOST_PLAYERS)) { - pluginManager.registerEvents(injector.getSingleton(DoubleLoginFixListener.class), this); - } - if (settings.getProperty(SecuritySettings.ADVANCED_SHULKER_FIX) && !isClassLoaded("org.bukkit.event.player.PlayerCommandSendEvent")) { - pluginManager.registerEvents(injector.getSingleton(AdvancedShulkerFixListener.class), this); - } else if (settings.getProperty(SecuritySettings.ADVANCED_SHULKER_FIX) && isClassLoaded("org.bukkit.event.player.PlayerCommandSendEvent")) { - logger.warning("You are running an 1.13+ minecraft server, AdvancedShulkerFix won't enable."); - } - if (settings.getProperty(SecuritySettings.PURGE_DATA_ON_QUIT)) { - pluginManager.registerEvents(injector.getSingleton(PurgeListener.class), this); - } - } - - /** - * Stops the server or disables the plugin, as defined in the configuration. - */ - public void stopOrUnload() { - if (settings == null || settings.getProperty(SecuritySettings.STOP_SERVER_ON_PROBLEM)) { - getLogger().warning("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!"); - setEnabled(false); - getServer().shutdown(); - } else { - setEnabled(false); - } - } - - @Override - public void onDisable() { - // onDisable is also called when we prematurely abort, so any field may be null - OnShutdownPlayerSaver onShutdownPlayerSaver = injector == null - ? null - : injector.createIfHasDependencies(OnShutdownPlayerSaver.class); - if (onShutdownPlayerSaver != null) { - onShutdownPlayerSaver.saveAllPlayers(); - } - if (settings != null && settings.getProperty(EmailSettings.SHUTDOWN_MAIL)) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'.'MM'.'dd'.' HH:mm:ss"); - Date date = new Date(System.currentTimeMillis()); - emailService.sendShutDown(settings.getProperty(EmailSettings.SHUTDOWN_MAIL_ADDRESS),dateFormat.format(date)); - } - - // Do backup on stop if enabled - if (backupService != null) { - backupService.doBackup(BackupService.BackupCause.STOP); - } - - // Wait for tasks and close data source - new TaskCloser(database).run(); - - // Disabled correctly - Consumer infoLogMethod = logger == null ? getLogger()::info : logger::info; - infoLogMethod.accept("AuthMe " + this.getDescription().getVersion() + " is unloaded successfully!"); - ConsoleLogger.closeFileWriter(); - } - - private void checkForUpdates() { - logger.info("Checking for updates..."); - Updater updater = new Updater(pluginBuild + pluginBuildNumber); - bukkitService.runTaskAsynchronously(() -> { - if (updater.isUpdateAvailable()) { - String message = "New version available! Latest:" + updater.getLatestVersion() + " Current:" + pluginBuild + pluginBuildNumber; - logger.warning(message); - logger.warning("Download from here: https://modrinth.com/plugin/authmerereloaded"); - } else { - logger.info("You are running the latest version."); - } - }); - } - - - private void checkServerType() { - if (isClassLoaded("io.papermc.paper.threadedregions.RegionizedServer")) { - logger.info("AuthMeReReloaded is running on Folia"); - } else if (isClassLoaded("com.destroystokyo.paper.PaperConfig")) { - logger.info("AuthMeReReloaded is running on Paper"); - } else if (isClassLoaded("catserver.server.CatServerConfig")) { - logger.info("AuthMeReReloaded is running on CatServer"); - } else if (isClassLoaded("org.spigotmc.SpigotConfig")) { - logger.info("AuthMeReReloaded is running on Spigot"); - } else if (isClassLoaded("org.bukkit.craftbukkit.CraftServer")) { - logger.info("AuthMeReReloaded is running on Bukkit"); - } else { - logger.info("AuthMeReReloaded is running on Unknown*"); - } - } - - - /** - * Handle Bukkit commands. - * - * @param sender The command sender (Bukkit). - * @param cmd The command (Bukkit). - * @param commandLabel The command label (Bukkit). - * @param args The command arguments (Bukkit). - * @return True if the command was executed, false otherwise. - */ - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, - @NotNull String commandLabel, String[] args) { - // Make sure the command handler has been initialized - if (commandHandler == null) { - getLogger().severe("AuthMe command handler is not available"); - return false; - } - - // Handle the command - return commandHandler.processCommand(sender, commandLabel, args); - } - - private String getServerNameVersionSafe() { - try { - Server server = getServer(); - return server.getName() + " v. " + server.getVersion(); - } catch (Throwable ignore) { - return "-"; - } - } -} diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java deleted file mode 100644 index 1b1d6788..00000000 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ /dev/null @@ -1,287 +0,0 @@ -package fr.xephi.authme; - -import com.google.common.base.Throwables; -import fr.xephi.authme.output.LogLevel; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.ExceptionUtils; - -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.text.MessageFormat; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.util.function.Supplier; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AuthMe logger. - */ -public final class ConsoleLogger { - - private static final String NEW_LINE = System.getProperty("line.separator"); - /** Formatter which formats dates to something like "[08-16 21:18:46]" for any given LocalDateTime. */ - private static final DateTimeFormatter DATE_FORMAT = new DateTimeFormatterBuilder() - .appendLiteral('[') - .appendPattern("MM-dd HH:mm:ss") - .appendLiteral(']') - .toFormatter(); - - // Outside references - private static File logFile; - private static Logger logger; - - // Shared state - private static OutputStreamWriter fileWriter; - - // Individual state - private final String name; - private LogLevel logLevel = LogLevel.INFO; - - /** - * Constructor. - * - * @param name the name of this logger (the fully qualified class name using it) - */ - public ConsoleLogger(String name) { - this.name = name; - } - - // -------- - // Configurations - // -------- - - public static void initialize(Logger logger, File logFile) { - ConsoleLogger.logger = logger; - ConsoleLogger.logFile = logFile; - } - - /** - * Sets logging settings which are shared by all logger instances. - * - * @param settings the settings to read from - */ - public static void initializeSharedSettings(Settings settings) { - boolean useLogging = settings.getProperty(SecuritySettings.USE_LOGGING); - if (useLogging) { - initializeFileWriter(); - } else { - closeFileWriter(); - } - } - - /** - * Sets logging settings which are individual to all loggers. - * - * @param settings the settings to read from - */ - public void initializeSettings(Settings settings) { - this.logLevel = settings.getProperty(PluginSettings.LOG_LEVEL); - } - - public LogLevel getLogLevel() { - return logLevel; - } - - public String getName() { - return name; - } - - - // -------- - // Logging methods - // -------- - - /** - * Log a WARN message. - * - * @param message The message to log - */ - public void warning(String message) { - logger.warning(message); - writeLog("[WARN] " + message); - } - - /** - * Log a Throwable with the provided message on WARNING level - * and save the stack trace to the log file. - * - * @param message The message to accompany the exception - * @param th The Throwable to log - */ - public void logException(String message, Throwable th) { - warning(message + " " + ExceptionUtils.formatException(th)); - writeLog(Throwables.getStackTraceAsString(th)); - } - - /** - * Log an INFO message. - * - * @param message The message to log - */ - public void info(String message) { - logger.info(message); - writeLog("[INFO] " + message); - } - - /** - * Log a FINE message if enabled. - *

- * Implementation note: this logs a message on INFO level because - * levels below INFO are disabled by Bukkit/Spigot. - * - * @param message The message to log - */ - public void fine(String message) { - if (logLevel.includes(LogLevel.FINE)) { - logger.info(message); - writeLog("[INFO:FINE] " + message); - } - } - - // -------- - // Debug log methods - // -------- - - /** - * Log a DEBUG message if enabled. - *

- * Implementation note: this logs a message on INFO level and prefixes it with "DEBUG" because - * levels below INFO are disabled by Bukkit/Spigot. - * - * @param message The message to log - */ - public void debug(String message) { - if (logLevel.includes(LogLevel.DEBUG)) { - logAndWriteWithDebugPrefix(message); - } - } - - /** - * Log the DEBUG message. - * - * @param message the message - * @param param1 parameter to replace in the message - */ - // Avoids array creation if DEBUG level is disabled - public void debug(String message, Object param1) { - if (logLevel.includes(LogLevel.DEBUG)) { - debug(message, new Object[]{param1}); - } - } - - /** - * Log the DEBUG message. - * - * @param message the message - * @param param1 first param to replace in message - * @param param2 second param to replace in message - */ - // Avoids array creation if DEBUG level is disabled - public void debug(String message, Object param1, Object param2) { - if (logLevel.includes(LogLevel.DEBUG)) { - debug(message, new Object[]{param1, param2}); - } - } - - /** - * Log the DEBUG message. - * - * @param message the message - * @param params the params to replace in the message - */ - public void debug(String message, Object... params) { - if (logLevel.includes(LogLevel.DEBUG)) { - logAndWriteWithDebugPrefix(MessageFormat.format(message, params)); - } - } - - /** - * Log the DEBUG message from the supplier if enabled. - * - * @param msgSupplier the message supplier - */ - public void debug(Supplier msgSupplier) { - if (logLevel.includes(LogLevel.DEBUG)) { - logAndWriteWithDebugPrefix(msgSupplier.get()); - } - } - - private void logAndWriteWithDebugPrefix(String message) { - String debugMessage = "[INFO:DEBUG] " + message; - logger.info(debugMessage); - writeLog(debugMessage); - } - - // -------- - // Helpers - // -------- - - /** - * Closes the file writer. - */ - public static void closeFileWriter() { - if (fileWriter != null) { - try { - fileWriter.flush(); - } catch (IOException ignored) { - } finally { - closeSafely(fileWriter); - fileWriter = null; - } - } - } - - /** - * Write a message into the log file with a TimeStamp if enabled. - * - * @param message The message to write to the log - */ - private static void writeLog(String message) { - if (fileWriter != null) { - String dateTime = DATE_FORMAT.format(LocalDateTime.now()); - try { - fileWriter.write(dateTime); - fileWriter.write(": "); - fileWriter.write(message); - fileWriter.write(NEW_LINE); - fileWriter.flush(); - } catch (IOException ignored) { - } - } - } - - private static void closeSafely(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException e) { - logger.log(Level.SEVERE, "Failed to close resource", e); - } - } - } - - /** - * Populates the {@link #fileWriter} field if it is null, handling any exceptions that might - * arise during its creation. - */ - private static void initializeFileWriter() { - if (fileWriter == null) { - FileOutputStream fos = null; - try { - fos = new FileOutputStream(logFile, true); - fileWriter = new OutputStreamWriter(fos, StandardCharsets.UTF_8); - } catch (Exception e) { - closeSafely(fos); - logger.log(Level.SEVERE, "Failed to create writer to AuthMe log file", e); - } - } - } -} diff --git a/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java b/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java deleted file mode 100644 index 27743d5d..00000000 --- a/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java +++ /dev/null @@ -1,397 +0,0 @@ -package fr.xephi.authme.api.v3; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams; -import fr.xephi.authme.process.register.executors.RegistrationMethod; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.GeoIpService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryView; - -import javax.inject.Inject; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Optional; - -import static fr.xephi.authme.listener.PlayerListener.PENDING_INVENTORIES; - -/** - * The current API of AuthMe. - * - * Recommended method of retrieving the AuthMeApi object: - * - * AuthMeApi authmeApi = AuthMeApi.getInstance(); - * - */ -@SuppressWarnings("unused") -public class AuthMeApi { - - private static AuthMeApi singleton; - private final AuthMe plugin; - private final DataSource dataSource; - private final PasswordSecurity passwordSecurity; - private final Management management; - private final ValidationService validationService; - private final PlayerCache playerCache; - private final GeoIpService geoIpService; - - /* - * Constructor for AuthMeApi. - */ - @Inject - AuthMeApi(AuthMe plugin, DataSource dataSource, PlayerCache playerCache, PasswordSecurity passwordSecurity, - Management management, ValidationService validationService, GeoIpService geoIpService) { - this.plugin = plugin; - this.dataSource = dataSource; - this.passwordSecurity = passwordSecurity; - this.management = management; - this.validationService = validationService; - this.playerCache = playerCache; - this.geoIpService = geoIpService; - AuthMeApi.singleton = this; - } - - /** - * Get the AuthMeApi object for AuthMe. - * - * @return The AuthMeApi object, or null if the AuthMe plugin is not enabled or not fully initialized yet - */ - public static AuthMeApi getInstance() { - return singleton; - } - - /** - * Return the plugin instance. - * - * @return The AuthMe instance - */ - public AuthMe getPlugin() { - return plugin; - } - - /** - * Gather the version number of the plugin. - * This can be used to determine whether certain AuthMeApi features are available or not. - * - * @return Plugin version identifier as a string. - */ - public String getPluginVersion() { - return AuthMe.getPluginVersion(); - } - - /** - * Return whether the given player is authenticated. - * - * @param player The player to verify - * @return true if the player is authenticated - */ - public boolean isAuthenticated(Player player) { - return playerCache.isAuthenticated(player.getName()); - } - - /** - * Check whether the given player is an NPC. - * - * @param player The player to verify - * @return true if the player is an npc - */ - public boolean isNpc(Player player) { - return PlayerUtils.isNpc(player); - } - - /** - * Check whether the given player is unrestricted. For such players, AuthMe will not require - * them to authenticate. - * - * @param player The player to verify - * @return true if the player is unrestricted - * @see fr.xephi.authme.settings.properties.RestrictionSettings#UNRESTRICTED_NAMES - */ - public boolean isUnrestricted(Player player) { - return validationService.isUnrestricted(player.getName()); - } - - /** - * Get the last location of an online player. - * - * @param player The player to process - * @return The location of the player - */ - public Location getLastLocation(Player player) { - PlayerAuth auth = playerCache.getAuth(player.getName()); - if (auth != null) { - return new Location(Bukkit.getWorld(auth.getWorld()), - auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getYaw(), auth.getPitch()); - } - return null; - } - - /** - * Returns the AuthMe info of the given player's name, or empty optional if the player doesn't exist. - * - * @param playerName The player name to look up - * @return AuthMe player info, or empty optional if the player doesn't exist - */ - public Optional getPlayerInfo(String playerName) { - PlayerAuth auth = playerCache.getAuth(playerName); - if (auth == null) { - auth = dataSource.getAuth(playerName); - } - return AuthMePlayerImpl.fromPlayerAuth(auth); - } - - /** - * Get the last ip address of a player. - * - * @param playerName The name of the player to process - * @return The last ip address of the player - */ - public String getLastIp(String playerName) { - PlayerAuth auth = playerCache.getAuth(playerName); - if (auth == null) { - auth = dataSource.getAuth(playerName); - } - if (auth != null) { - return auth.getLastIp(); - } - return null; - } - - /** - * Get user names by ip. - * - * @param address The ip address to process - * @return The list of user names related to the ip address - */ - public List getNamesByIp(String address) { - return dataSource.getAllAuthsByIp(address); - } - - /** - * Get the last (AuthMe) login date of a player. - * - * @param playerName The name of the player to process - * @return The date of the last login, or null if the player doesn't exist or has never logged in - * @deprecated Use Java 8's Instant method {@link #getLastLoginTime(String)} - */ - @Deprecated - public Date getLastLogin(String playerName) { - Long lastLogin = getLastLoginMillis(playerName); - return lastLogin == null ? null : new Date(lastLogin); - } - - /** - * Get the last (AuthMe) login timestamp of a player. - * - * @param playerName The name of the player to process - * - * @return The timestamp of the last login, or null if the player doesn't exist or has never logged in - */ - public Instant getLastLoginTime(String playerName) { - Long lastLogin = getLastLoginMillis(playerName); - return lastLogin == null ? null : Instant.ofEpochMilli(lastLogin); - } - - private Long getLastLoginMillis(String playerName) { - PlayerAuth auth = playerCache.getAuth(playerName); - if (auth == null) { - auth = dataSource.getAuth(playerName); - } - if (auth != null) { - return auth.getLastLogin(); - } - return null; - } - - /** - * Return whether the player is registered. - * - * @param playerName The player name to check - * @return true if player is registered, false otherwise - */ - public boolean isRegistered(String playerName) { - String player = playerName.toLowerCase(Locale.ROOT); - return dataSource.isAuthAvailable(player); - } - - /** - * Check the password for the given player. - * - * @param playerName The player to check the password for - * @param passwordToCheck The password to check - * @return true if the password is correct, false otherwise - */ - public boolean checkPassword(String playerName, String passwordToCheck) { - return passwordSecurity.comparePassword(passwordToCheck, playerName); - } - - /** - * Register an OFFLINE/ONLINE player with the given password. - * - * @param playerName The player to register - * @param password The password to register the player with - * - * @return true if the player was registered successfully - */ - public boolean registerPlayer(String playerName, String password) { - String name = playerName.toLowerCase(Locale.ROOT); - if (isRegistered(name)) { - return false; - } - HashedPassword result = passwordSecurity.computeHash(password, name); - PlayerAuth auth = PlayerAuth.builder() - .name(name) - .password(result) - .realName(playerName) - .registrationDate(System.currentTimeMillis()) - .build(); - return dataSource.saveAuth(auth); - } - - /** - * Open an inventory for the given player at any time. - * - * @param player The player to open the inventory for - * @param inventory The inventory to open - * @return The inventory view - */ - public InventoryView openInventory(Player player, Inventory inventory) { - PENDING_INVENTORIES.add(inventory); - return player.openInventory(inventory); - } - - /** - * Force a player to login, i.e. the player is logged in without needing his password. - * - * @param player The player to log in - */ - public void forceLogin(Player player) { - management.forceLogin(player); - } - - /** - * Force a player to login, i.e. the player is logged in without needing his password. - * - * @param player The player to log in - * @param quiet Whether to suppress the login message - */ - public void forceLogin(Player player, boolean quiet) { - management.forceLogin(player, quiet); - } - - /** - * Force a player to logout. - * - * @param player The player to log out - */ - public void forceLogout(Player player) { - management.performLogout(player); - } - - /** - * 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) { - management.performRegister(RegistrationMethod.API_REGISTRATION, - ApiPasswordRegisterParams.of(player, password, autoLogin)); - } - - /** - * Register an ONLINE player with the given password. - * - * @param player The player to register - * @param password The password to use - */ - public void forceRegister(Player player, String password) { - forceRegister(player, password, true); - } - - /** - * Unregister a player from AuthMe. - * - * @param player The player to unregister - */ - public void forceUnregister(Player player) { - management.performUnregisterByAdmin(null, player.getName(), player); - } - - /** - * Unregister a player from AuthMe by name. - * - * @param name the name of the player (case-insensitive) - */ - public void forceUnregister(String name) { - management.performUnregisterByAdmin(null, name, Bukkit.getPlayer(name)); - } - - /** - * Change a user's password - * - * @param name the user name - * @param newPassword the new password - */ - public void changePassword(String name, String newPassword) { - management.performPasswordChangeAsAdmin(null, name, newPassword); - } - - /** - * Get all the registered names (lowercase) - * - * @return registered names - */ - public List getRegisteredNames() { - List registeredNames = new ArrayList<>(); - dataSource.getAllAuths().forEach(auth -> registeredNames.add(auth.getNickname())); - return registeredNames; - } - - /** - * Get all the registered real-names (original case) - * - * @return registered real-names - */ - public List getRegisteredRealNames() { - List registeredNames = new ArrayList<>(); - dataSource.getAllAuths().forEach(auth -> registeredNames.add(auth.getRealName())); - return registeredNames; - } - - /** - * Get the country code of the given IP address. - * - * @param ip textual IP address to lookup. - * - * @return two-character ISO 3166-1 alpha code for the country. - */ - public String getCountryCode(String ip) { - return geoIpService.getCountryCode(ip); - } - - /** - * Get the country name of the given IP address. - * - * @param ip textual IP address to lookup. - * - * @return The name of the country. - */ - public String getCountryName(String ip) { - return geoIpService.getCountryName(ip); - } -} diff --git a/src/main/java/fr/xephi/authme/api/v3/AuthMePlayer.java b/src/main/java/fr/xephi/authme/api/v3/AuthMePlayer.java deleted file mode 100644 index 4c64073b..00000000 --- a/src/main/java/fr/xephi/authme/api/v3/AuthMePlayer.java +++ /dev/null @@ -1,65 +0,0 @@ -package fr.xephi.authme.api.v3; - -import java.time.Instant; -import java.util.Optional; -import java.util.UUID; - -/** - * Read-only player info exposed in the AuthMe API. The data in this object is copied from the - * database and not updated afterwards. As such, it may become outdated if the player data changes - * in AuthMe. - * - * @see AuthMeApi#getPlayerInfo - */ -public interface AuthMePlayer { - - /** - * @return the case-sensitive name of the player, e.g. "thePlayer3030" - never null - */ - String getName(); - - /** - * Returns the UUID of the player as given by the server (may be offline UUID or not). - * The UUID is not present if AuthMe is configured not to store the UUID or if the data is not - * present (e.g. older record). - * - * @return player uuid, or empty optional if not available - */ - Optional getUuid(); - - /** - * Returns the email address associated with this player, or an empty optional if not available. - * - * @return player's email or empty optional - */ - Optional getEmail(); - - /** - * @return the registration date of the player's account - never null - */ - Instant getRegistrationDate(); - - /** - * Returns the IP address with which the player's account was registered. Returns an empty optional - * for older accounts, or if the account was registered by someone else (e.g. by an admin). - * - * @return the ip address used during the registration of the account, or empty optional - */ - Optional getRegistrationIpAddress(); - - /** - * Returns the last login date of the player. An empty optional is returned if the player never logged in. - * - * @return date the player last logged in successfully, or empty optional if not applicable - */ - Optional getLastLoginDate(); - - /** - * Returns the IP address the player last logged in with successfully. Returns an empty optional if the - * player never logged in. - * - * @return ip address the player last logged in with successfully, or empty optional if not applicable - */ - Optional getLastLoginIpAddress(); - -} diff --git a/src/main/java/fr/xephi/authme/api/v3/AuthMePlayerImpl.java b/src/main/java/fr/xephi/authme/api/v3/AuthMePlayerImpl.java deleted file mode 100644 index 9ea0b643..00000000 --- a/src/main/java/fr/xephi/authme/api/v3/AuthMePlayerImpl.java +++ /dev/null @@ -1,93 +0,0 @@ -package fr.xephi.authme.api.v3; - -import fr.xephi.authme.data.auth.PlayerAuth; - -import java.time.Instant; -import java.util.Optional; -import java.util.UUID; - -/** - * Implementation of {@link AuthMePlayer}. This implementation is not part of the API and - * may have breaking changes in subsequent releases. - */ -class AuthMePlayerImpl implements AuthMePlayer { - - private String name; - private UUID uuid; - private String email; - - private Instant registrationDate; - private String registrationIpAddress; - - private Instant lastLoginDate; - private String lastLoginIpAddress; - - AuthMePlayerImpl() { - } - - /** - * Maps the given player auth to an AuthMePlayer instance. Returns an empty optional if - * the player auth is null. - * - * @param playerAuth the player auth or null - * @return the mapped player auth, or empty optional if the argument was null - */ - static Optional fromPlayerAuth(PlayerAuth playerAuth) { - if (playerAuth == null) { - return Optional.empty(); - } - - AuthMePlayerImpl authMeUser = new AuthMePlayerImpl(); - authMeUser.name = playerAuth.getRealName(); - authMeUser.uuid = playerAuth.getUuid(); - authMeUser.email = nullIfDefault(playerAuth.getEmail(), PlayerAuth.DB_EMAIL_DEFAULT); - Long lastLoginMillis = nullIfDefault(playerAuth.getLastLogin(), PlayerAuth.DB_LAST_LOGIN_DEFAULT); - authMeUser.registrationDate = toInstant(playerAuth.getRegistrationDate()); - authMeUser.registrationIpAddress = playerAuth.getRegistrationIp(); - authMeUser.lastLoginDate = toInstant(lastLoginMillis); - authMeUser.lastLoginIpAddress = nullIfDefault(playerAuth.getLastIp(), PlayerAuth.DB_LAST_IP_DEFAULT); - return Optional.of(authMeUser); - } - - @Override - public String getName() { - return name; - } - - public Optional getUuid() { - return Optional.ofNullable(uuid); - } - - @Override - public Optional getEmail() { - return Optional.ofNullable(email); - } - - @Override - public Instant getRegistrationDate() { - return registrationDate; - } - - @Override - public Optional getRegistrationIpAddress() { - return Optional.ofNullable(registrationIpAddress); - } - - @Override - public Optional getLastLoginDate() { - return Optional.ofNullable( lastLoginDate); - } - - @Override - public Optional getLastLoginIpAddress() { - return Optional.ofNullable(lastLoginIpAddress); - } - - private static Instant toInstant(Long epochMillis) { - return epochMillis == null ? null : Instant.ofEpochMilli(epochMillis); - } - - private static T nullIfDefault(T value, T defaultValue) { - return defaultValue.equals(value) ? null : value; - } -} diff --git a/src/main/java/fr/xephi/authme/command/CommandArgumentDescription.java b/src/main/java/fr/xephi/authme/command/CommandArgumentDescription.java deleted file mode 100644 index 9ae3da4b..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandArgumentDescription.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.command; - -/** - * Wrapper for the description of a command argument. - */ -public class CommandArgumentDescription { - - /** - * Argument name (one-word description of the argument). - */ - private final String name; - /** - * Argument description. - */ - private final String description; - /** - * Defines whether the argument is optional. - */ - private final boolean isOptional; - - /** - * Constructor. - * - * @param name The argument name. - * @param description The argument description. - * @param isOptional True if the argument is optional, false otherwise. - */ - public CommandArgumentDescription(String name, String description, boolean isOptional) { - this.name = name; - this.description = description; - this.isOptional = isOptional; - } - - /** - * Get the argument name. - * - * @return Argument name. - */ - public String getName() { - return this.name; - } - - /** - * Get the argument description. - * - * @return Argument description. - */ - public String getDescription() { - return description; - } - - /** - * Return whether the argument is optional. - * - * @return True if the argument is optional, false otherwise. - */ - public boolean isOptional() { - return isOptional; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/CommandDescription.java b/src/main/java/fr/xephi/authme/command/CommandDescription.java deleted file mode 100644 index 040894f9..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandDescription.java +++ /dev/null @@ -1,294 +0,0 @@ -package fr.xephi.authme.command; - -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Utils; - -import java.util.ArrayList; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Arrays.asList; - -/** - * 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. - *

- * 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 - * {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that - * the child defines. - */ -@SuppressWarnings("checkstyle:FinalClass") // Justification: class is mocked in multiple tests -public class CommandDescription { - - /** - * Defines the labels to execute the command. For example, if labels are "register" and "r" and the parent is - * the command for "/authme", then both "/authme register" and "/authme r" will be handled by this command. - */ - private List labels; - /** - * Short description of the command. - */ - private String description; - /** - * Detailed description of what the command does. - */ - private String detailedDescription; - /** - * The class implementing the command described by this object. - */ - private Class executableCommand; - /** - * The parent command. - */ - private CommandDescription parent; - /** - * The child commands that extend this command. - */ - private List children = new ArrayList<>(); - /** - * The arguments the command takes. - */ - private List arguments; - /** - * Permission node required to execute this command. - */ - private PermissionNode permission; - - /** - * Private constructor. - *

- * Note for developers: Instances should be created with {@link CommandBuilder#register()} to be properly - * registered in the command tree. - * - * @param labels command labels - * @param description description of the command - * @param detailedDescription detailed command description - * @param executableCommand class of the command implementation - * @param parent parent command - * @param arguments command arguments - * @param permission permission node required to execute this command - */ - private CommandDescription(List labels, String description, String detailedDescription, - Class executableCommand, CommandDescription parent, - List arguments, PermissionNode permission) { - this.labels = labels; - this.description = description; - this.detailedDescription = detailedDescription; - this.executableCommand = executableCommand; - this.parent = parent; - this.arguments = arguments; - this.permission = permission; - } - - /** - * Return all relative labels of this command. For example, if this object describes {@code /authme register} and - * {@code /authme r}, then it will return a list with {@code register} and {@code r}. The parent label - * {@code authme} is not returned. - * - * @return All labels of the command description. - */ - public List getLabels() { - return labels; - } - - /** - * Check whether this command description has the given label. - * - * @param commandLabel The label to check for. - * - * @return {@code true} if this command contains the given label, {@code false} otherwise. - */ - public boolean hasLabel(String commandLabel) { - for (String label : labels) { - if (label.equalsIgnoreCase(commandLabel)) { - return true; - } - } - return false; - } - - /** - * Return the {@link ExecutableCommand} class implementing this command. - * - * @return The executable command class - */ - public Class getExecutableCommand() { - return executableCommand; - } - - /** - * Return the parent. - * - * @return The parent command, or null for base commands - */ - public CommandDescription getParent() { - return parent; - } - - /** - * Return the number of labels necessary to get to this command. This corresponds to the number of parents + 1. - * - * @return The number of labels, e.g. for "/authme abc def" the label count is 3 - */ - public int getLabelCount() { - if (parent == null) { - return 1; - } - return parent.getLabelCount() + 1; - } - - /** - * Return all command children. - * - * @return Command children. - */ - public List getChildren() { - return children; - } - - /** - * Return all arguments the command takes. - * - * @return Command arguments. - */ - public List getArguments() { - return arguments; - } - - /** - * Return a short description of the command. - * - * @return Command description. - */ - public String getDescription() { - return description; - } - - /** - * Return a detailed description of the command. - * - * @return Detailed description. - */ - public String getDetailedDescription() { - return detailedDescription; - } - - /** - * Return the permission node required to execute the command. - * - * @return The permission node, or null if none are required to execute the command. - */ - public PermissionNode getPermission() { - return permission; - } - - /** - * Return a builder instance to create a new command description. - * - * @return The builder - */ - public static CommandBuilder builder() { - return new CommandBuilder(); - } - - /** - * Builder for initializing CommandDescription objects. - */ - public static final class CommandBuilder { - private List labels; - private String description; - private String detailedDescription; - private Class executableCommand; - private CommandDescription parent; - private List arguments = new ArrayList<>(); - private PermissionNode permission; - - /** - * Build a CommandDescription and register it onto the parent if available. - * - * @return The generated CommandDescription object - */ - public CommandDescription register() { - CommandDescription command = build(); - - if (command.parent != null) { - command.parent.children.add(command); - } - return command; - } - - /** - * Build a CommandDescription (without registering it on the parent). - * - * @return The generated CommandDescription object - */ - public CommandDescription build() { - checkArgument(!Utils.isCollectionEmpty(labels), "Labels may not be empty"); - checkArgument(!StringUtils.isBlank(description), "Description may not be empty"); - checkArgument(!StringUtils.isBlank(detailedDescription), "Detailed description may not be empty"); - checkArgument(executableCommand != null, "Executable command must be set"); - // parents and permissions may be null; arguments may be empty - - return new CommandDescription(labels, description, detailedDescription, executableCommand, - parent, arguments, permission); - } - - public CommandBuilder labels(List labels) { - this.labels = labels; - return this; - } - - public CommandBuilder labels(String... labels) { - return labels(asList(labels)); - } - - public CommandBuilder description(String description) { - this.description = description; - return this; - } - - public CommandBuilder detailedDescription(String detailedDescription) { - this.detailedDescription = detailedDescription; - return this; - } - - public CommandBuilder executableCommand(Class executableCommand) { - this.executableCommand = executableCommand; - return this; - } - - public CommandBuilder parent(CommandDescription parent) { - this.parent = parent; - return this; - } - - /** - * Add an argument that the command description requires. This method can be called multiples times to add - * multiple arguments. - * - * @param label The label of the argument (single word name of the argument) - * @param description The description of the argument - * @param isOptional True if the argument is optional, false if it is mandatory - * - * @return The builder - */ - public CommandBuilder withArgument(String label, String description, boolean isOptional) { - arguments.add(new CommandArgumentDescription(label, description, isOptional)); - return this; - } - - /** - * Add a permission node that a user must have to execute the command. - * - * @param permission The PermissionNode to add - * @return The builder - */ - public CommandBuilder permission(PermissionNode permission) { - this.permission = permission; - return this; - } - } - -} diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java deleted file mode 100644 index 08629c6f..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandHandler.java +++ /dev/null @@ -1,186 +0,0 @@ -package fr.xephi.authme.command; - -import ch.jalu.injector.factory.Factory; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -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 invoking the correct {@link ExecutableCommand} based on incoming - * command labels or for displaying a help message for unknown command labels. - */ -public class CommandHandler { - - /** - * The threshold for suggesting a similar command. If the difference is below this value, we will - * ask the player whether he meant the similar command. - */ - private static final double SUGGEST_COMMAND_THRESHOLD = 0.75; - - private final CommandMapper commandMapper; - private final PermissionsManager permissionsManager; - private final Messages messages; - private final HelpProvider helpProvider; - - /** - * Map with ExecutableCommand children. The key is the type of the value. - */ - private Map, ExecutableCommand> commands = new HashMap<>(); - - @Inject - CommandHandler(Factory commandFactory, CommandMapper commandMapper, - PermissionsManager permissionsManager, Messages messages, HelpProvider helpProvider) { - this.commandMapper = commandMapper; - this.permissionsManager = permissionsManager; - this.messages = messages; - this.helpProvider = helpProvider; - initializeCommands(commandFactory, commandMapper.getCommandClasses()); - } - - /** - * Map a command that was invoked to the proper {@link CommandDescription} or return a useful error - * message upon failure. - * - * @param sender The command sender. - * @param bukkitCommandLabel The command label (Bukkit). - * @param bukkitArgs The command arguments (Bukkit). - * - * @return True if the command was executed, false otherwise. - */ - public boolean processCommand(CommandSender sender, String bukkitCommandLabel, String[] bukkitArgs) { - // Add the Bukkit command label to the front so we get a list like [authme, register, bobby, mysecret] - List parts = skipEmptyArguments(bukkitArgs); - parts.add(0, bukkitCommandLabel); - - FoundCommandResult result = commandMapper.mapPartsToCommand(sender, parts); - handleCommandResult(sender, result); - return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus()); - } - - /** - * Processes the given {@link FoundCommandResult} for the provided command sender. - * - * @param sender the command sender who executed the command - * @param result the command mapping result - */ - private void handleCommandResult(CommandSender sender, FoundCommandResult result) { - switch (result.getResultStatus()) { - case SUCCESS: - executeCommand(sender, result); - break; - case MISSING_BASE_COMMAND: - sender.sendMessage(ChatColor.DARK_RED + "Failed to parse " + AuthMe.getPluginName() + " command!"); - break; - case INCORRECT_ARGUMENTS: - sendImproperArgumentsMessage(sender, result); - break; - case UNKNOWN_LABEL: - sendUnknownCommandMessage(sender, result); - break; - case NO_PERMISSION: - messages.send(sender, MessageKey.NO_PERMISSION); - break; - default: - throw new IllegalStateException("Unknown result status '" + result.getResultStatus() + "'"); - } - } - - /** - * Initialize all required ExecutableCommand objects. - * - * @param commandFactory factory to create command objects - * @param commandClasses the classes to instantiate - */ - private void initializeCommands(Factory commandFactory, - Set> commandClasses) { - for (Class clazz : commandClasses) { - commands.put(clazz, commandFactory.newInstance(clazz)); - } - } - - /** - * Execute the command for the given command sender. - * - * @param sender The sender which initiated the command - * @param result The mapped result - */ - private void executeCommand(CommandSender sender, FoundCommandResult result) { - ExecutableCommand executableCommand = commands.get(result.getCommandDescription().getExecutableCommand()); - List arguments = result.getArguments(); - executableCommand.executeCommand(sender, arguments); - } - - /** - * Skip all entries of the given array that are simply whitespace. - * - * @param args The array to process - * @return List of the items that are not empty - */ - private static List skipEmptyArguments(String[] args) { - List cleanArguments = new ArrayList<>(); - for (String argument : args) { - if (!StringUtils.isBlank(argument)) { - cleanArguments.add(argument); - } - } - return cleanArguments; - } - - /** - * Show an "unknown command" message to the user and suggest an existing command if its similarity is within - * the defined threshold. - * - * @param sender The command sender - * @param result The command that was found during the mapping process - */ - private static void sendUnknownCommandMessage(CommandSender sender, FoundCommandResult result) { - sender.sendMessage(ChatColor.DARK_RED + "Unknown command!"); - - // Show a command suggestion if available and the difference isn't too big - if (result.getDifference() <= SUGGEST_COMMAND_THRESHOLD && result.getCommandDescription() != null) { - sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD - + CommandUtils.constructCommandPath(result.getCommandDescription()) + ChatColor.YELLOW + "?"); - } - - sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + result.getLabels().get(0) - + " help" + ChatColor.YELLOW + " to view help."); - } - - private void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result) { - CommandDescription command = result.getCommandDescription(); - if (!permissionsManager.hasPermission(sender, command.getPermission())) { - messages.send(sender, MessageKey.NO_PERMISSION); - return; - } - - ExecutableCommand executableCommand = commands.get(command.getExecutableCommand()); - MessageKey usageMessage = executableCommand.getArgumentsMismatchMessage(); - if (usageMessage == null) { - showHelpForCommand(sender, result); - } else { - messages.send(sender, usageMessage); - } - } - - private void showHelpForCommand(CommandSender sender, FoundCommandResult result) { - sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!"); - helpProvider.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS); - - List labels = result.getLabels(); - String childLabel = labels.size() >= 2 ? labels.get(1) : ""; - sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE - + "/" + labels.get(0) + " help " + childLabel); - } -} diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java deleted file mode 100644 index fcc3ce61..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ /dev/null @@ -1,652 +0,0 @@ -package fr.xephi.authme.command; - -import com.google.common.collect.ImmutableList; -import fr.xephi.authme.command.executable.HelpCommand; -import fr.xephi.authme.command.executable.authme.AccountsCommand; -import fr.xephi.authme.command.executable.authme.AuthMeCommand; -import fr.xephi.authme.command.executable.authme.BackupCommand; -import fr.xephi.authme.command.executable.authme.ChangePasswordAdminCommand; -import fr.xephi.authme.command.executable.authme.ConverterCommand; -import fr.xephi.authme.command.executable.authme.FirstSpawnCommand; -import fr.xephi.authme.command.executable.authme.ForceLoginCommand; -import fr.xephi.authme.command.executable.authme.GetEmailCommand; -import fr.xephi.authme.command.executable.authme.GetIpCommand; -import fr.xephi.authme.command.executable.authme.LastLoginCommand; -import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand; -import fr.xephi.authme.command.executable.authme.PurgeCommand; -import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand; -import fr.xephi.authme.command.executable.authme.PurgePlayerCommand; -import fr.xephi.authme.command.executable.authme.RecentPlayersCommand; -import fr.xephi.authme.command.executable.authme.RegisterAdminCommand; -import fr.xephi.authme.command.executable.authme.ReloadCommand; -import fr.xephi.authme.command.executable.authme.SetEmailCommand; -import fr.xephi.authme.command.executable.authme.SetFirstSpawnCommand; -import fr.xephi.authme.command.executable.authme.SetSpawnCommand; -import fr.xephi.authme.command.executable.authme.SpawnCommand; -import fr.xephi.authme.command.executable.authme.SwitchAntiBotCommand; -import fr.xephi.authme.command.executable.authme.TotpDisableAdminCommand; -import fr.xephi.authme.command.executable.authme.TotpViewStatusCommand; -import fr.xephi.authme.command.executable.authme.UnregisterAdminCommand; -import fr.xephi.authme.command.executable.authme.UpdateHelpMessagesCommand; -import fr.xephi.authme.command.executable.authme.VersionCommand; -import fr.xephi.authme.command.executable.authme.debug.DebugCommand; -import fr.xephi.authme.command.executable.captcha.CaptchaCommand; -import fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand; -import fr.xephi.authme.command.executable.email.AddEmailCommand; -import fr.xephi.authme.command.executable.email.ChangeEmailCommand; -import fr.xephi.authme.command.executable.email.EmailBaseCommand; -import fr.xephi.authme.command.executable.email.EmailSetPasswordCommand; -import fr.xephi.authme.command.executable.email.ProcessCodeCommand; -import fr.xephi.authme.command.executable.email.RecoverEmailCommand; -import fr.xephi.authme.command.executable.email.ShowEmailCommand; -import fr.xephi.authme.command.executable.login.LoginCommand; -import fr.xephi.authme.command.executable.logout.LogoutCommand; -import fr.xephi.authme.command.executable.register.RegisterCommand; -import fr.xephi.authme.command.executable.totp.AddTotpCommand; -import fr.xephi.authme.command.executable.totp.ConfirmTotpCommand; -import fr.xephi.authme.command.executable.totp.RemoveTotpCommand; -import fr.xephi.authme.command.executable.totp.TotpBaseCommand; -import fr.xephi.authme.command.executable.totp.TotpCodeCommand; -import fr.xephi.authme.command.executable.unregister.UnregisterCommand; -import fr.xephi.authme.command.executable.verification.VerificationCommand; -import fr.xephi.authme.permission.AdminPermission; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PlayerPermission; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -/** - * Initializes all available AuthMe commands. - */ -public class CommandInitializer { - - private static final boolean OPTIONAL = true; - private static final boolean MANDATORY = false; - - private List commands; - - public CommandInitializer() { - buildCommands(); - } - - /** - * Returns the description of all AuthMe commands. - * - * @return the command descriptions - */ - public List getCommands() { - return commands; - } - - /** - * Builds the command description objects for all available AuthMe commands. - */ - private void buildCommands() { - // Register /authme and /email commands - CommandDescription authMeBase = buildAuthMeBaseCommand(); - CommandDescription emailBase = buildEmailBaseCommand(); - - // Register the base login command - CommandDescription loginBase = CommandDescription.builder() - .parent(null) - .labels("login", "l", "log") - .description("Login command") - .detailedDescription("Command to log in using AuthMeReloaded.") - .withArgument("password", "Login password", MANDATORY) - .permission(PlayerPermission.LOGIN) - .executableCommand(LoginCommand.class) - .register(); - - // Register the base logout command - CommandDescription logoutBase = CommandDescription.builder() - .parent(null) - .labels("logout") - .description("Logout command") - .detailedDescription("Command to logout using AuthMeReloaded.") - .permission(PlayerPermission.LOGOUT) - .executableCommand(LogoutCommand.class) - .register(); - - // Register the base register command - CommandDescription registerBase = CommandDescription.builder() - .parent(null) - .labels("register", "reg") - .description("Register an account") - .detailedDescription("Command to register using AuthMeReloaded.") - .withArgument("password", "Password", OPTIONAL) - .withArgument("verifyPassword", "Verify password", OPTIONAL) - .permission(PlayerPermission.REGISTER) - .executableCommand(RegisterCommand.class) - .register(); - - // Register the base unregister command - CommandDescription unregisterBase = CommandDescription.builder() - .parent(null) - .labels("unregister", "unreg") - .description("Unregister an account") - .detailedDescription("Command to unregister using AuthMeReloaded.") - .withArgument("password", "Password", MANDATORY) - .permission(PlayerPermission.UNREGISTER) - .executableCommand(UnregisterCommand.class) - .register(); - - // Register the base changepassword command - CommandDescription changePasswordBase = CommandDescription.builder() - .parent(null) - .labels("changepassword", "changepass", "cp") - .description("Change password of an account") - .detailedDescription("Command to change your password using AuthMeReloaded.") - .withArgument("oldPassword", "Old password", MANDATORY) - .withArgument("newPassword", "New password", MANDATORY) - .permission(PlayerPermission.CHANGE_PASSWORD) - .executableCommand(ChangePasswordCommand.class) - .register(); - - // Create totp base command - CommandDescription totpBase = buildTotpBaseCommand(); - - // Register the base captcha command - CommandDescription captchaBase = CommandDescription.builder() - .parent(null) - .labels("captcha") - .description("Captcha command") - .detailedDescription("Captcha command for AuthMeReloaded.") - .withArgument("captcha", "The Captcha", MANDATORY) - .permission(PlayerPermission.CAPTCHA) - .executableCommand(CaptchaCommand.class) - .register(); - - // Register the base verification code command - CommandDescription verificationBase = CommandDescription.builder() - .parent(null) - .labels("verification") - .description("Verification command") - .detailedDescription("Command to complete the verification process for AuthMeReloaded.") - .withArgument("code", "The code", MANDATORY) - .permission(PlayerPermission.VERIFICATION_CODE) - .executableCommand(VerificationCommand.class) - .register(); - - List baseCommands = ImmutableList.of(authMeBase, emailBase, loginBase, logoutBase, - registerBase, unregisterBase, changePasswordBase, totpBase, captchaBase, verificationBase); - - setHelpOnAllBases(baseCommands); - commands = baseCommands; - } - - /** - * Creates a command description object for {@code /authme} including its children. - * - * @return the authme base command description - */ - private CommandDescription buildAuthMeBaseCommand() { - // Register the base AuthMe Reloaded command - CommandDescription authmeBase = CommandDescription.builder() - .labels("authme") - .description("AuthMe op commands") - .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.") - .executableCommand(AuthMeCommand.class) - .register(); - - // Register the register command - CommandDescription.builder() - .parent(authmeBase) - .labels("register", "reg", "r") - .description("Register a player") - .detailedDescription("Register the specified player with the specified password.") - .withArgument("player", "Player name", MANDATORY) - .withArgument("password", "Password", MANDATORY) - .permission(AdminPermission.REGISTER) - .executableCommand(RegisterAdminCommand.class) - .register(); - - // Register the unregister command - CommandDescription.builder() - .parent(authmeBase) - .labels("unregister", "unreg", "unr") - .description("Unregister a player") - .detailedDescription("Unregister the specified player.") - .withArgument("player", "Player name", MANDATORY) - .permission(AdminPermission.UNREGISTER) - .executableCommand(UnregisterAdminCommand.class) - .register(); - - // Register the forcelogin command - CommandDescription.builder() - .parent(authmeBase) - .labels("forcelogin", "login") - .description("Enforce login player") - .detailedDescription("Enforce the specified player to login.") - .withArgument("player", "Online player name", OPTIONAL) - .permission(AdminPermission.FORCE_LOGIN) - .executableCommand(ForceLoginCommand.class) - .register(); - - // Register the changepassword command - CommandDescription.builder() - .parent(authmeBase) - .labels("password", "changepassword", "changepass", "cp") - .description("Change a player's password") - .detailedDescription("Change the password of a player.") - .withArgument("player", "Player name", MANDATORY) - .withArgument("pwd", "New password", MANDATORY) - .permission(AdminPermission.CHANGE_PASSWORD) - .executableCommand(ChangePasswordAdminCommand.class) - .register(); - - // Register the last login command - CommandDescription.builder() - .parent(authmeBase) - .labels("lastlogin", "ll") - .description("Player's last login") - .detailedDescription("View the date of the specified players last login.") - .withArgument("player", "Player name", OPTIONAL) - .permission(AdminPermission.LAST_LOGIN) - .executableCommand(LastLoginCommand.class) - .register(); - - // Register the accounts command - CommandDescription.builder() - .parent(authmeBase) - .labels("accounts", "account") - .description("Display player accounts") - .detailedDescription("Display all accounts of a player by his player name or IP.") - .withArgument("player", "Player name or IP", OPTIONAL) - .permission(AdminPermission.ACCOUNTS) - .executableCommand(AccountsCommand.class) - .register(); - - // Register the getemail command - CommandDescription.builder() - .parent(authmeBase) - .labels("email", "mail", "getemail", "getmail") - .description("Display player's email") - .detailedDescription("Display the email address of the specified player if set.") - .withArgument("player", "Player name", OPTIONAL) - .permission(AdminPermission.GET_EMAIL) - .executableCommand(GetEmailCommand.class) - .register(); - - // Register the setemail command - CommandDescription.builder() - .parent(authmeBase) - .labels("setemail", "setmail", "chgemail", "chgmail") - .description("Change player's email") - .detailedDescription("Change the email address of the specified player.") - .withArgument("player", "Player name", MANDATORY) - .withArgument("email", "Player email", MANDATORY) - .permission(AdminPermission.CHANGE_EMAIL) - .executableCommand(SetEmailCommand.class) - .register(); - - // Register the getip command - CommandDescription.builder() - .parent(authmeBase) - .labels("getip", "ip") - .description("Get player's IP") - .detailedDescription("Get the IP address of the specified online player.") - .withArgument("player", "Player name", MANDATORY) - .permission(AdminPermission.GET_IP) - .executableCommand(GetIpCommand.class) - .register(); - - // Register totp command - CommandDescription.builder() - .parent(authmeBase) - .labels("totp", "2fa") - .description("See if a player has enabled TOTP") - .detailedDescription("Returns whether the specified player has enabled two-factor authentication.") - .withArgument("player", "Player name", MANDATORY) - .permission(AdminPermission.VIEW_TOTP_STATUS) - .executableCommand(TotpViewStatusCommand.class) - .register(); - - // Register disable totp command - CommandDescription.builder() - .parent(authmeBase) - .labels("disabletotp", "disable2fa", "deletetotp", "delete2fa") - .description("Delete TOTP token of a player") - .detailedDescription("Disable two-factor authentication for a player.") - .withArgument("player", "Player name", MANDATORY) - .permission(AdminPermission.DISABLE_TOTP) - .executableCommand(TotpDisableAdminCommand.class) - .register(); - - // Register the spawn command - CommandDescription.builder() - .parent(authmeBase) - .labels("spawn", "home") - .description("Teleport to spawn") - .detailedDescription("Teleport to the spawn.") - .permission(AdminPermission.SPAWN) - .executableCommand(SpawnCommand.class) - .register(); - - // Register the setspawn command - CommandDescription.builder() - .parent(authmeBase) - .labels("setspawn", "chgspawn") - .description("Change the spawn") - .detailedDescription("Change the player's spawn to your current position.") - .permission(AdminPermission.SET_SPAWN) - .executableCommand(SetSpawnCommand.class) - .register(); - - // Register the firstspawn command - CommandDescription.builder() - .parent(authmeBase) - .labels("firstspawn", "firsthome") - .description("Teleport to first spawn") - .detailedDescription("Teleport to the first spawn.") - .permission(AdminPermission.FIRST_SPAWN) - .executableCommand(FirstSpawnCommand.class) - .register(); - - // Register the setfirstspawn command - CommandDescription.builder() - .parent(authmeBase) - .labels("setfirstspawn", "chgfirstspawn") - .description("Change the first spawn") - .detailedDescription("Change the first player's spawn to your current position.") - .permission(AdminPermission.SET_FIRST_SPAWN) - .executableCommand(SetFirstSpawnCommand.class) - .register(); - - // Register the purge command - CommandDescription.builder() - .parent(authmeBase) - .labels("purge", "delete") - .description("Purge old data") - .detailedDescription("Purge old AuthMeReloaded data longer than the specified number of days ago.") - .withArgument("days", "Number of days", MANDATORY) - .permission(AdminPermission.PURGE) - .executableCommand(PurgeCommand.class) - .register(); - - // Purge player command - CommandDescription.builder() - .parent(authmeBase) - .labels("purgeplayer") - .description("Purges the data of one player") - .detailedDescription("Purges data of the given player.") - .withArgument("player", "The player to purge", MANDATORY) - .withArgument("options", "'force' to run without checking if player is registered", OPTIONAL) - .permission(AdminPermission.PURGE_PLAYER) - .executableCommand(PurgePlayerCommand.class) - .register(); - - // Backup command - CommandDescription.builder() - .parent(authmeBase) - .labels("backup") - .description("Perform a backup") - .detailedDescription("Creates a backup of the registered users.") - .permission(AdminPermission.BACKUP) - .executableCommand(BackupCommand.class) - .register(); - - // Register the purgelastposition command - CommandDescription.builder() - .parent(authmeBase) - .labels("resetpos", "purgelastposition", "purgelastpos", "resetposition", - "resetlastposition", "resetlastpos") - .description("Purge player's last position") - .detailedDescription("Purge the last know position of the specified player or all of them.") - .withArgument("player/*", "Player name or * for all players", MANDATORY) - .permission(AdminPermission.PURGE_LAST_POSITION) - .executableCommand(PurgeLastPositionCommand.class) - .register(); - - // Register the purgebannedplayers command - CommandDescription.builder() - .parent(authmeBase) - .labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer") - .description("Purge banned players data") - .detailedDescription("Purge all AuthMeReloaded data for banned players.") - .permission(AdminPermission.PURGE_BANNED_PLAYERS) - .executableCommand(PurgeBannedPlayersCommand.class) - .register(); - - // Register the switchantibot command - CommandDescription.builder() - .parent(authmeBase) - .labels("switchantibot", "toggleantibot", "antibot") - .description("Switch AntiBot mode") - .detailedDescription("Switch or toggle the AntiBot mode to the specified state.") - .withArgument("mode", "ON / OFF", OPTIONAL) - .permission(AdminPermission.SWITCH_ANTIBOT) - .executableCommand(SwitchAntiBotCommand.class) - .register(); - - // Register the reload command - CommandDescription.builder() - .parent(authmeBase) - .labels("reload", "rld") - .description("Reload plugin") - .detailedDescription("Reload the AuthMeReloaded plugin.") - .permission(AdminPermission.RELOAD) - .executableCommand(ReloadCommand.class) - .register(); - - // Register the version command - CommandDescription.builder() - .parent(authmeBase) - .labels("version", "ver", "v", "about", "info") - .description("Version info") - .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the " - + "developers, contributors, and license.") - .executableCommand(VersionCommand.class) - .register(); - - CommandDescription.builder() - .parent(authmeBase) - .labels("converter", "convert", "conv") - .description("Converter command") - .detailedDescription("Converter command for AuthMeReloaded.") - .withArgument("job", "Conversion job: xauth / crazylogin / rakamak / " - + "royalauth / vauth / sqliteToSql / mysqlToSqlite / loginsecurity", OPTIONAL) - .permission(AdminPermission.CONVERTER) - .executableCommand(ConverterCommand.class) - .register(); - - CommandDescription.builder() - .parent(authmeBase) - .labels("messages", "msg") - .description("Add missing help messages") - .detailedDescription("Adds missing texts to the current help messages file.") - .permission(AdminPermission.UPDATE_MESSAGES) - .executableCommand(UpdateHelpMessagesCommand.class) - .register(); - - CommandDescription.builder() - .parent(authmeBase) - .labels("recent") - .description("See players who have recently logged in") - .detailedDescription("Shows the last players that have logged in.") - .permission(AdminPermission.SEE_RECENT_PLAYERS) - .executableCommand(RecentPlayersCommand.class) - .register(); - - CommandDescription.builder() - .parent(authmeBase) - .labels("debug", "dbg") - .description("Debug features") - .detailedDescription("Allows various operations for debugging.") - .withArgument("child", "The child to execute", OPTIONAL) - .withArgument("arg", "argument (depends on debug section)", OPTIONAL) - .withArgument("arg", "argument (depends on debug section)", OPTIONAL) - .permission(DebugSectionPermissions.DEBUG_COMMAND) - .executableCommand(DebugCommand.class) - .register(); - - return authmeBase; - } - - /** - * Creates a command description for {@code /email} including its children. - * - * @return the email base command description - */ - private CommandDescription buildEmailBaseCommand() { - // Register the base Email command - CommandDescription emailBase = CommandDescription.builder() - .parent(null) - .labels("email") - .description("Add email or recover password") - .detailedDescription("The AuthMeReloaded email command base.") - .executableCommand(EmailBaseCommand.class) - .register(); - - // Register the show command - CommandDescription.builder() - .parent(emailBase) - .labels("show", "myemail") - .description("Show Email") - .detailedDescription("Show your current email address.") - .permission(PlayerPermission.SEE_EMAIL) - .executableCommand(ShowEmailCommand.class) - .register(); - - // Register the add command - CommandDescription.builder() - .parent(emailBase) - .labels("add", "addemail", "addmail") - .description("Add Email") - .detailedDescription("Add a new email address to your account.") - .withArgument("email", "Email address", MANDATORY) - .withArgument("verifyEmail", "Email address verification", MANDATORY) - .permission(PlayerPermission.ADD_EMAIL) - .executableCommand(AddEmailCommand.class) - .register(); - - // Register the change command - CommandDescription.builder() - .parent(emailBase) - .labels("change", "changeemail", "changemail") - .description("Change Email") - .detailedDescription("Change an email address of your account.") - .withArgument("oldEmail", "Old email address", MANDATORY) - .withArgument("newEmail", "New email address", MANDATORY) - .permission(PlayerPermission.CHANGE_EMAIL) - .executableCommand(ChangeEmailCommand.class) - .register(); - - // Register the recover command - CommandDescription.builder() - .parent(emailBase) - .labels("recover", "recovery", "recoveremail", "recovermail") - .description("Recover password using email") - .detailedDescription("Recover your account using an Email address by sending a mail containing " - + "a new password.") - .withArgument("email", "Email address", MANDATORY) - .permission(PlayerPermission.RECOVER_EMAIL) - .executableCommand(RecoverEmailCommand.class) - .register(); - - // Register the process recovery code command - CommandDescription.builder() - .parent(emailBase) - .labels("code") - .description("Submit code to recover password") - .detailedDescription("Recover your account by submitting a code delivered to your email.") - .withArgument("code", "Recovery code", MANDATORY) - .permission(PlayerPermission.RECOVER_EMAIL) - .executableCommand(ProcessCodeCommand.class) - .register(); - - // Register the change password after recovery command - CommandDescription.builder() - .parent(emailBase) - .labels("setpassword") - .description("Set new password after recovery") - .detailedDescription("Set a new password after successfully recovering your account.") - .withArgument("password", "New password", MANDATORY) - .permission(PlayerPermission.RECOVER_EMAIL) - .executableCommand(EmailSetPasswordCommand.class) - .register(); - - return emailBase; - } - - /** - * Creates a command description object for {@code /totp} including its children. - * - * @return the totp base command description - */ - private CommandDescription buildTotpBaseCommand() { - // Register the base totp command - CommandDescription totpBase = CommandDescription.builder() - .parent(null) - .labels("totp", "2fa") - .description("TOTP commands") - .detailedDescription("Performs actions related to two-factor authentication.") - .executableCommand(TotpBaseCommand.class) - .register(); - - // Register the base totp code - CommandDescription.builder() - .parent(totpBase) - .labels("code", "c") - .description("Command for logging in") - .detailedDescription("Processes the two-factor authentication code during login.") - .withArgument("code", "The TOTP code to use to log in", MANDATORY) - .executableCommand(TotpCodeCommand.class) - .register(); - - // Register totp add - CommandDescription.builder() - .parent(totpBase) - .labels("add") - .description("Enables TOTP") - .detailedDescription("Enables two-factor authentication for your account.") - .permission(PlayerPermission.ENABLE_TWO_FACTOR_AUTH) - .executableCommand(AddTotpCommand.class) - .register(); - - // Register totp confirm - CommandDescription.builder() - .parent(totpBase) - .labels("confirm") - .description("Enables TOTP after successful code") - .detailedDescription("Saves the generated TOTP secret after confirmation.") - .withArgument("code", "Code from the given secret from /totp add", MANDATORY) - .permission(PlayerPermission.ENABLE_TWO_FACTOR_AUTH) - .executableCommand(ConfirmTotpCommand.class) - .register(); - - // Register totp remove - CommandDescription.builder() - .parent(totpBase) - .labels("remove") - .description("Removes TOTP") - .detailedDescription("Disables two-factor authentication for your account.") - .withArgument("code", "Current 2FA code", MANDATORY) - .permission(PlayerPermission.DISABLE_TWO_FACTOR_AUTH) - .executableCommand(RemoveTotpCommand.class) - .register(); - - return totpBase; - } - - /** - * 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 - */ - private void setHelpOnAllBases(Collection commands) { - final List helpCommandLabels = Arrays.asList("help", "hlp", "h", "sos", "?"); - - for (CommandDescription base : commands) { - CommandDescription.builder() - .parent(base) - .labels(helpCommandLabels) - .description("View help") - .detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.") - .withArgument("query", "The command or query to view help for.", OPTIONAL) - .executableCommand(HelpCommand.class) - .register(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java deleted file mode 100644 index 5beb5e33..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandMapper.java +++ /dev/null @@ -1,207 +0,0 @@ -package fr.xephi.authme.command; - -import fr.xephi.authme.command.executable.HelpCommand; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Utils; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import static fr.xephi.authme.command.FoundResultStatus.INCORRECT_ARGUMENTS; -import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND; -import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL; - -/** - * Maps incoming command parts to the correct {@link CommandDescription}. - */ -public class CommandMapper { - - /** - * The class of the help command, to which the base label should also be passed in the arguments. - */ - private static final Class HELP_COMMAND_CLASS = HelpCommand.class; - - private final Collection baseCommands; - private final PermissionsManager permissionsManager; - - @Inject - public CommandMapper(CommandInitializer commandInitializer, PermissionsManager permissionsManager) { - this.baseCommands = commandInitializer.getCommands(); - this.permissionsManager = permissionsManager; - } - - - /** - * Map incoming command parts to a command. This processes all parts and distinguishes the labels from arguments. - * - * @param sender The command sender (null if none applicable) - * @param parts The parts to map to commands and arguments - * @return The generated {@link FoundCommandResult} - */ - public FoundCommandResult mapPartsToCommand(CommandSender sender, List parts) { - if (Utils.isCollectionEmpty(parts)) { - return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND); - } - - CommandDescription base = getBaseCommand(parts.get(0)); - if (base == null) { - return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND); - } - - // Prefer labels: /register help goes to "Help command", not "Register command" with argument 'help' - List remainingParts = parts.subList(1, parts.size()); - CommandDescription childCommand = getSuitableChild(base, remainingParts); - if (childCommand != null) { - FoundResultStatus status = getPermissionAwareStatus(sender, childCommand); - FoundCommandResult result = new FoundCommandResult( - childCommand, parts.subList(0, 2), parts.subList(2, parts.size()), 0.0, status); - return transformResultForHelp(result); - } else if (hasSuitableArgumentCount(base, remainingParts.size())) { - FoundResultStatus status = getPermissionAwareStatus(sender, base); - return new FoundCommandResult(base, parts.subList(0, 1), parts.subList(1, parts.size()), 0.0, status); - } - - return getCommandWithSmallestDifference(base, parts); - } - - /** - * Return all {@link ExecutableCommand} classes referenced in {@link CommandDescription} objects. - * - * @return all classes - * @see CommandInitializer#getCommands - */ - public Set> getCommandClasses() { - Set> classes = new HashSet<>(50); - for (CommandDescription command : baseCommands) { - classes.add(command.getExecutableCommand()); - for (CommandDescription child : command.getChildren()) { - classes.add(child.getExecutableCommand()); - } - } - return classes; - } - - /** - * Return the command whose label matches the given parts the best. This method is called when - * a successful mapping could not be performed. - * - * @param base the base command - * @param parts the command parts - * @return the closest result - */ - private static FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List parts) { - // Return the base command with incorrect arg count error if we only have one part - if (parts.size() <= 1) { - return new FoundCommandResult(base, parts, new ArrayList<>(), 0.0, INCORRECT_ARGUMENTS); - } - - final String childLabel = parts.get(1); - double minDifference = Double.POSITIVE_INFINITY; - CommandDescription closestCommand = null; - - for (CommandDescription child : base.getChildren()) { - double difference = getLabelDifference(child, childLabel); - if (difference < minDifference) { - minDifference = difference; - closestCommand = child; - } - } - - // base command may have no children, in which case we return the base command with incorrect arguments error - if (closestCommand == null) { - return new FoundCommandResult( - base, parts.subList(0, 1), parts.subList(1, parts.size()), 0.0, INCORRECT_ARGUMENTS); - } - - FoundResultStatus status = (minDifference == 0.0) ? INCORRECT_ARGUMENTS : UNKNOWN_LABEL; - final int partsSize = parts.size(); - List labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize)); - List arguments = (labels.size() == partsSize) - ? new ArrayList<>() - : parts.subList(labels.size(), partsSize); - - return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status); - } - - private CommandDescription getBaseCommand(String label) { - String baseLabel = label.toLowerCase(Locale.ROOT); - if (baseLabel.startsWith("authme:")) { - baseLabel = baseLabel.substring("authme:".length()); - } - for (CommandDescription command : baseCommands) { - if (command.hasLabel(baseLabel)) { - return command; - } - } - return null; - } - - /** - * Return a child from a base command if the label and the argument count match. - * - * @param baseCommand The base command whose children should be checked - * @param parts The command parts received from the invocation; the first item is the potential label and any - * other items are command arguments. The first initial part that led to the base command should not - * be present. - * - * @return A command if there was a complete match (including proper argument count), null otherwise - */ - private static CommandDescription getSuitableChild(CommandDescription baseCommand, List parts) { - if (Utils.isCollectionEmpty(parts)) { - return null; - } - - final String label = parts.get(0).toLowerCase(Locale.ROOT); - final int argumentCount = parts.size() - 1; - - for (CommandDescription child : baseCommand.getChildren()) { - if (child.hasLabel(label) && hasSuitableArgumentCount(child, argumentCount)) { - return child; - } - } - return null; - } - - private static FoundCommandResult transformResultForHelp(FoundCommandResult result) { - if (result.getCommandDescription() != null - && HELP_COMMAND_CLASS == result.getCommandDescription().getExecutableCommand()) { - // 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], - // so we can use the arguments as the labels to the command to show help for - List arguments = new ArrayList<>(result.getArguments()); - arguments.add(0, result.getLabels().get(0)); - return new FoundCommandResult(result.getCommandDescription(), result.getLabels(), - arguments, result.getDifference(), result.getResultStatus()); - } - return result; - } - - private FoundResultStatus getPermissionAwareStatus(CommandSender sender, CommandDescription command) { - if (sender != null && !permissionsManager.hasPermission(sender, command.getPermission())) { - return FoundResultStatus.NO_PERMISSION; - } - return FoundResultStatus.SUCCESS; - } - - private static boolean hasSuitableArgumentCount(CommandDescription command, int argumentCount) { - int minArgs = CommandUtils.getMinNumberOfArguments(command); - int maxArgs = CommandUtils.getMaxNumberOfArguments(command); - - return argumentCount >= minArgs && argumentCount <= maxArgs; - } - - private static double getLabelDifference(CommandDescription command, String givenLabel) { - return command.getLabels().stream() - .map(label -> StringUtils.getDifference(label, givenLabel)) - .min(Double::compareTo) - .orElseThrow(() -> new IllegalStateException("Command does not have any labels set")); - } - -} diff --git a/src/main/java/fr/xephi/authme/command/CommandUtils.java b/src/main/java/fr/xephi/authme/command/CommandUtils.java deleted file mode 100644 index 595f23ab..00000000 --- a/src/main/java/fr/xephi/authme/command/CommandUtils.java +++ /dev/null @@ -1,109 +0,0 @@ -package fr.xephi.authme.command; - -import com.google.common.collect.Lists; -import org.bukkit.ChatColor; - -import java.util.ArrayList; -import java.util.List; - -/** - * Utility functions for {@link CommandDescription} objects. - */ -public final class CommandUtils { - - private CommandUtils() { - } - - /** - * Returns the minimum number of arguments required for running the command (= number of mandatory arguments). - * - * @param command the command to process - * @return min number of arguments required by the command - */ - public static int getMinNumberOfArguments(CommandDescription command) { - int mandatoryArguments = 0; - for (CommandArgumentDescription argument : command.getArguments()) { - if (!argument.isOptional()) { - ++mandatoryArguments; - } - } - return mandatoryArguments; - } - - /** - * Returns the maximum number of arguments the command accepts. - * - * @param command the command to process - * @return max number of arguments that may be passed to the command - */ - public static int getMaxNumberOfArguments(CommandDescription command) { - return command.getArguments().size(); - } - - /** - * Constructs a hierarchical list of commands for the given command. The commands are in order: - * the parents of the given command precede the provided command. For example, given the command - * for {@code /authme register}, a list with {@code [{authme}, {authme register}]} is returned. - * - * @param command the command to build a parent list for - * @return the parent list - */ - public static List constructParentList(CommandDescription command) { - List commands = new ArrayList<>(); - CommandDescription currentCommand = command; - while (currentCommand != null) { - commands.add(currentCommand); - currentCommand = currentCommand.getParent(); - } - return Lists.reverse(commands); - } - - /** - * Returns a textual representation of the command, e.g. {@code /authme register}. - * - * @param command the command to create the path for - * @return the command string - */ - public static String constructCommandPath(CommandDescription command) { - StringBuilder sb = new StringBuilder(); - String prefix = "/"; - for (CommandDescription ancestor : constructParentList(command)) { - sb.append(prefix).append(ancestor.getLabels().get(0)); - prefix = " "; - } - return sb.toString(); - } - - /** - * Constructs a command path with color formatting, based on the supplied labels. This includes - * the command's arguments, as defined in the provided command description. The list of labels - * must contain all labels to be used. - * - * @param command the command to read arguments from - * @param correctLabels the labels to use (must be complete) - * @return formatted command syntax incl. arguments - */ - public static String buildSyntax(CommandDescription command, List correctLabels) { - StringBuilder commandSyntax = new StringBuilder(ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW); - for (int i = 1; i < correctLabels.size(); ++i) { - commandSyntax.append(" ").append(correctLabels.get(i)); - } - for (CommandArgumentDescription argument : command.getArguments()) { - commandSyntax.append(" ").append(formatArgument(argument)); - } - return commandSyntax.toString(); - } - - /** - * Formats a command argument with the proper type of brackets. - * - * @param argument the argument to format - * @return the formatted argument - */ - public static String formatArgument(CommandArgumentDescription argument) { - if (argument.isOptional()) { - return "[" + argument.getName() + "]"; - } - return "<" + argument.getName() + ">"; - } -} diff --git a/src/main/java/fr/xephi/authme/command/ExecutableCommand.java b/src/main/java/fr/xephi/authme/command/ExecutableCommand.java deleted file mode 100644 index 54ee9e84..00000000 --- a/src/main/java/fr/xephi/authme/command/ExecutableCommand.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.xephi.authme.command; - -import fr.xephi.authme.message.MessageKey; -import org.bukkit.command.CommandSender; - -import java.util.List; - -/** - * Base class for AuthMe commands that can be executed. - */ -public interface ExecutableCommand { - - /** - * Executes the command with the given arguments. - * - * @param sender the command sender (initiator of the command) - * @param arguments the arguments - */ - void executeCommand(CommandSender sender, List arguments); - - /** - * Returns the message to show to the user if the command is used with the wrong arguments. - * If null is returned, the standard help (/command help) output is shown. - * - * @return the message explaining the command's usage, or {@code null} for default behavior - */ - default MessageKey getArgumentsMismatchMessage() { - return null; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/FoundCommandResult.java b/src/main/java/fr/xephi/authme/command/FoundCommandResult.java deleted file mode 100644 index 520eec24..00000000 --- a/src/main/java/fr/xephi/authme/command/FoundCommandResult.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.xephi.authme.command; - -import java.util.List; - -/** - * Result of a command mapping by {@link CommandHandler}. An object of this class represents a successful mapping - * as well as erroneous ones, as communicated with {@link FoundResultStatus}. - *

- * Fields other than {@link FoundResultStatus} are available depending, among other factors, on the status: - *

    - *
  • {@link FoundResultStatus#SUCCESS} entails that mapping the input to a command was successful. Therefore, - * the command description, labels and arguments are set. The difference is 0.0.
  • - *
  • {@link FoundResultStatus#INCORRECT_ARGUMENTS}: The received parts could be mapped to a command but the argument - * count doesn't match. Guarantees that the command description field is not null; difference is 0.0
  • - *
  • {@link FoundResultStatus#UNKNOWN_LABEL}: The labels could not be mapped to a command. The command description - * may be set to the most similar command, or it may be null. Difference is above 0.0.
  • - *
  • {@link FoundResultStatus#NO_PERMISSION}: The command could be matched properly but the sender does not have - * permission to execute it.
  • - *
  • {@link FoundResultStatus#MISSING_BASE_COMMAND} should never occur. All other fields may be null and any further - * processing of the object should be aborted.
  • - *
- */ -public class FoundCommandResult { - - /** - * The command description instance. - */ - private final CommandDescription commandDescription; - /** - * The labels used to invoke the command. This may be different for the same {@link ExecutableCommand} instance - * if multiple labels have been defined, e.g. "/authme register" and "/authme reg". - */ - private final List labels; - /** The command arguments. */ - private final List arguments; - /** The difference between the matched command and the supplied labels. */ - private final double difference; - /** The status of the result (see class description). */ - private final FoundResultStatus resultStatus; - - /** - * Constructor. - * - * @param commandDescription The command description. - * @param labels The labels used to access the command. - * @param arguments The command arguments. - * @param difference The difference between the supplied labels and the matched command. - * @param resultStatus The status of the result. - */ - public FoundCommandResult(CommandDescription commandDescription, List labels, List arguments, - double difference, FoundResultStatus resultStatus) { - this.commandDescription = commandDescription; - this.labels = labels; - this.arguments = arguments; - this.difference = difference; - this.resultStatus = resultStatus; - } - - public CommandDescription getCommandDescription() { - return this.commandDescription; - } - - public List getArguments() { - return this.arguments; - } - - public List getLabels() { - return this.labels; - } - - public double getDifference() { - return difference; - } - - public FoundResultStatus getResultStatus() { - return resultStatus; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/FoundResultStatus.java b/src/main/java/fr/xephi/authme/command/FoundResultStatus.java deleted file mode 100644 index 32ca6b7b..00000000 --- a/src/main/java/fr/xephi/authme/command/FoundResultStatus.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.xephi.authme.command; - -/** - * Result status for mapping command parts. See {@link FoundCommandResult} for a detailed description of the states. - */ -public enum FoundResultStatus { - - SUCCESS, - - INCORRECT_ARGUMENTS, - - UNKNOWN_LABEL, - - NO_PERMISSION, - - MISSING_BASE_COMMAND - -} diff --git a/src/main/java/fr/xephi/authme/command/PlayerCommand.java b/src/main/java/fr/xephi/authme/command/PlayerCommand.java deleted file mode 100644 index 8ce6e05f..00000000 --- a/src/main/java/fr/xephi/authme/command/PlayerCommand.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.xephi.authme.command; - -import org.bukkit.command.CommandSender; -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. - */ -public abstract class PlayerCommand implements ExecutableCommand { - - @Override - public void executeCommand(CommandSender sender, List arguments) { - if (sender instanceof Player) { - runCommand((Player) sender, arguments); - } else { - String alternative = getAlternativeCommand(); - if (alternative != null) { - sender.sendMessage("Player only! Please use " + alternative + " instead."); - } else { - sender.sendMessage("This command is only for players."); - } - } - } - - /** - * Runs the command with the given player and arguments. - * - * @param player the player who initiated the command - * @param arguments the arguments supplied with the command - */ - protected abstract void runCommand(Player player, List arguments); - - /** - * Returns an alternative command (textual representation) that is not restricted to players only. - * Example: {@code "/authme register "} - * - * @return Alternative command not restricted to players, or null if not applicable - */ - protected String getAlternativeCommand() { - return null; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/TabCompleteHandler.java b/src/main/java/fr/xephi/authme/command/TabCompleteHandler.java deleted file mode 100644 index 36390084..00000000 --- a/src/main/java/fr/xephi/authme/command/TabCompleteHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.command; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -public class TabCompleteHandler implements TabCompleter { - - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { - return new ArrayList<>(); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java b/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java deleted file mode 100644 index 118994f0..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java +++ /dev/null @@ -1,64 +0,0 @@ -package fr.xephi.authme.command.executable; - -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.CommandUtils; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.command.FoundCommandResult; -import fr.xephi.authme.command.FoundResultStatus; -import fr.xephi.authme.command.help.HelpProvider; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -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.help.HelpProvider.ALL_OPTIONS; -import static fr.xephi.authme.command.help.HelpProvider.SHOW_ALTERNATIVES; -import static fr.xephi.authme.command.help.HelpProvider.SHOW_CHILDREN; -import static fr.xephi.authme.command.help.HelpProvider.SHOW_COMMAND; -import static fr.xephi.authme.command.help.HelpProvider.SHOW_DESCRIPTION; - -/** - * Displays help information to a user. - */ -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, - // e.g. "/authme help register" would typically be arguments = [register], but here we pass [authme, register] - @Override - public void executeCommand(CommandSender sender, List arguments) { - FoundCommandResult result = commandMapper.mapPartsToCommand(sender, arguments); - - FoundResultStatus resultStatus = result.getResultStatus(); - if (MISSING_BASE_COMMAND.equals(resultStatus)) { - sender.sendMessage(ChatColor.DARK_RED + "Could not get base command"); - return; - } else if (UNKNOWN_LABEL.equals(resultStatus)) { - if (result.getCommandDescription() == null) { - sender.sendMessage(ChatColor.DARK_RED + "Unknown command"); - return; - } else { - sender.sendMessage(ChatColor.GOLD + "Assuming " + ChatColor.WHITE - + CommandUtils.constructCommandPath(result.getCommandDescription())); - } - } - - int mappedCommandLevel = result.getCommandDescription().getLabelCount(); - if (mappedCommandLevel == 1) { - helpProvider.outputHelp(sender, result, - SHOW_COMMAND | SHOW_DESCRIPTION | SHOW_CHILDREN | SHOW_ALTERNATIVES); - } else { - helpProvider.outputHelp(sender, result, ALL_OPTIONS); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java deleted file mode 100644 index 20f6bff8..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -/** - * Shows all accounts registered by the same IP address for the given player name or IP address. - */ -public class AccountsCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private BukkitService bukkitService; - - @Inject - private CommonService commonService; - - @Override - public void executeCommand(final CommandSender sender, List arguments) { - // TODO #1366: last IP vs. registration IP? - final String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - - // Assumption: a player name cannot contain '.' - if (playerName.contains(".")) { - bukkitService.runTaskAsynchronously(() -> { - List accountList = dataSource.getAllAuthsByIp(playerName); - if (accountList.isEmpty()) { - sender.sendMessage("[AuthMe] This IP does not exist in the database."); - } else if (accountList.size() == 1) { - sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); - } else { - outputAccountsList(sender, playerName, accountList); - } - }); - } else { - bukkitService.runTaskAsynchronously(() -> { - PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase(Locale.ROOT)); - if (auth == null) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - return; - } else if (auth.getLastIp() == null) { - sender.sendMessage("No known last IP address for player"); - return; - } - - List accountList = dataSource.getAllAuthsByIp(auth.getLastIp()); - if (accountList.isEmpty()) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - } else if (accountList.size() == 1) { - sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); - } else { - outputAccountsList(sender, playerName, accountList); - } - }); - } - } - - private static void outputAccountsList(CommandSender sender, String playerName, List accountList) { - sender.sendMessage("[AuthMe] " + playerName + " has " + accountList.size() + " accounts."); - String message = "[AuthMe] " + String.join(", ", accountList) + "."; - sender.sendMessage(message); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/AuthMeCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/AuthMeCommand.java deleted file mode 100644 index 2648177e..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/AuthMeCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.command.ExecutableCommand; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import java.util.List; - -/** - * AuthMe base command; shows the version and some command pointers. - */ -public class AuthMeCommand implements ExecutableCommand { - - @Override - public void executeCommand(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.GREEN + "This server is running " + AuthMe.getPluginName() + " v" - + AuthMe.getPluginVersion() + " b" + AuthMe.getPluginBuildNumber()+ "! " + ChatColor.RED + "<3"); - sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/authme help" + ChatColor.YELLOW - + " to view help."); - sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/authme about" + ChatColor.YELLOW - + " to view about."); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/BackupCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/BackupCommand.java deleted file mode 100644 index 0e72fb60..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/BackupCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.service.BackupService; -import fr.xephi.authme.service.BackupService.BackupCause; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command to perform a backup. - */ -public class BackupCommand implements ExecutableCommand { - - @Inject - private BackupService backupService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - backupService.doBackup(BackupCause.COMMAND, sender); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java deleted file mode 100644 index 3c6264cc..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.ValidationService.ValidationResult; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Admin command for changing a player's password. - */ -public class ChangePasswordAdminCommand implements ExecutableCommand { - - @Inject - private ValidationService validationService; - - @Inject - private CommonService commonService; - - @Inject - private Management management; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Get the player and password - final String playerName = arguments.get(0); - final String playerPass = arguments.get(1); - - // Validate the password - ValidationResult validationResult = validationService.validatePassword(playerPass, playerName); - if (validationResult.hasError()) { - commonService.send(sender, validationResult.getMessageKey(), validationResult.getArgs()); - } else { - management.performPasswordChangeAsAdmin(sender, playerName, playerPass); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java deleted file mode 100644 index 15875ac9..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java +++ /dev/null @@ -1,95 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import ch.jalu.injector.factory.Factory; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableSortedMap; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.converter.Converter; -import fr.xephi.authme.datasource.converter.CrazyLoginConverter; -import fr.xephi.authme.datasource.converter.H2ToSqlite; -import fr.xephi.authme.datasource.converter.LoginSecurityConverter; -import fr.xephi.authme.datasource.converter.MySqlToSqlite; -import fr.xephi.authme.datasource.converter.RoyalAuthConverter; -import fr.xephi.authme.datasource.converter.SqliteToH2; -import fr.xephi.authme.datasource.converter.SqliteToSql; -import fr.xephi.authme.datasource.converter.XAuthConverter; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * Converter command: launches conversion based on its parameters. - */ -public class ConverterCommand implements ExecutableCommand { - - @VisibleForTesting - static final Map> CONVERTERS = getConverters(); - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ConverterCommand.class); - - @Inject - private CommonService commonService; - - @Inject - private BukkitService bukkitService; - - @Inject - private Factory converterFactory; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - Class converterClass = getConverterClassFromArgs(arguments); - if (converterClass == null) { - sender.sendMessage("Converters: " + String.join(", ", CONVERTERS.keySet())); - return; - } - - // Get the proper converter instance - final Converter converter = converterFactory.newInstance(converterClass); - - // Run the convert job - bukkitService.runTaskAsynchronously(() -> { - try { - converter.execute(sender); - } catch (Exception e) { - commonService.send(sender, MessageKey.ERROR); - logger.logException("Error during conversion:", e); - } - }); - - // Show a status message - sender.sendMessage("[AuthMe] Successfully started " + arguments.get(0)); - } - - private static Class getConverterClassFromArgs(List arguments) { - return arguments.isEmpty() - ? null - : CONVERTERS.get(arguments.get(0).toLowerCase(Locale.ROOT)); - } - - /** - * Initializes a map with all available converters. - * - * @return map with all available converters - */ - private static Map> getConverters() { - return ImmutableSortedMap.>naturalOrder() - .put("xauth", XAuthConverter.class) - .put("crazylogin", CrazyLoginConverter.class) - .put("royalauth", RoyalAuthConverter.class) - .put("sqlitetosql", SqliteToSql.class) - .put("mysqltosqlite", MySqlToSqlite.class) - .put("sqlitetoh2", SqliteToH2.class) - .put("h2tosqlite", H2ToSqlite.class) - .put("loginsecurity", LoginSecurityConverter.class) - .build(); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommand.java deleted file mode 100644 index 9eba3d15..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/FirstSpawnCommand.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.util.TeleportUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Teleports the player to the first spawn. - */ -public class FirstSpawnCommand extends PlayerCommand { - @Inject - private Settings settings; - @Inject - private SpawnLoader spawnLoader; - @Inject - private BukkitService bukkitService; - @Override - public void runCommand(Player player, List arguments) { - if (spawnLoader.getFirstSpawn() == null) { - player.sendMessage("[AuthMe] First spawn has failed, please try to define the first spawn"); - } else { - //String name= player.getName(); - bukkitService.runTaskIfFolia(player, () -> { - TeleportUtils.teleport(player, spawnLoader.getFirstSpawn()); - }); - //player.teleport(spawnLoader.getFirstSpawn()); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java deleted file mode 100644 index 3adcad45..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ForceLoginCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -import static fr.xephi.authme.permission.PlayerPermission.CAN_LOGIN_BE_FORCED; - -/** - * Forces the login of a player, i.e. logs the player in without the need of a (correct) password. - */ -public class ForceLoginCommand implements ExecutableCommand { - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private Management management; - - @Inject - private BukkitService bukkitService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Get the player query - String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - - Player player = bukkitService.getPlayerExact(playerName); - if (player == null || !player.isOnline()) { - sender.sendMessage("Player needs to be online!"); - } else if (!permissionsManager.hasPermission(player, CAN_LOGIN_BE_FORCED)) { - sender.sendMessage("You cannot force login the player " + playerName + "!"); - } else { - management.forceLogin(player); - sender.sendMessage("Force login for " + playerName + " performed!"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java deleted file mode 100644 index b6691438..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Returns a player's email. - */ -public class GetEmailCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - - DataSourceValue email = dataSource.getEmail(playerName); - if (email.rowExists()) { - sender.sendMessage("[AuthMe] " + playerName + "'s email: " + email.getValue()); - } else { - commonService.send(sender, MessageKey.UNKNOWN_USER); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java deleted file mode 100644 index 2e00c65e..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/GetIpCommand.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -public class GetIpCommand implements ExecutableCommand { - - @Inject - private BukkitService bukkitService; - - @Inject - private DataSource dataSource; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String playerName = arguments.get(0); - Player player = bukkitService.getPlayerExact(playerName); - PlayerAuth auth = dataSource.getAuth(playerName); - - if (player != null) { - sender.sendMessage("Current IP of " + player.getName() + " is " + PlayerUtils.getPlayerIp(player) - + ":" + player.getAddress().getPort()); - } - - if (auth == null) { - String displayName = player == null ? playerName : player.getName(); - sender.sendMessage(displayName + " is not registered in the database"); - } else { - sender.sendMessage("Database: last IP: " + auth.getLastIp() + ", registration IP: " - + auth.getRegistrationIp()); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java deleted file mode 100644 index f522e80f..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Date; -import java.util.List; - -/** - * Returns the last login date of the given user. - */ -public class LastLoginCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Get the player - String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - - PlayerAuth auth = dataSource.getAuth(playerName); - if (auth == null) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - return; - } - - // Get the last login date - final Long lastLogin = auth.getLastLogin(); - final String lastLoginDate = lastLogin == null ? "never" : new Date(lastLogin).toString(); - - // Show the player status - sender.sendMessage("[AuthMe] " + playerName + " last login: " + lastLoginDate); - if (lastLogin != null) { - sender.sendMessage("[AuthMe] The player " + playerName + " last logged in " - + createLastLoginIntervalMessage(lastLogin) + " ago"); - } - sender.sendMessage("[AuthMe] Last player's IP: " + auth.getLastIp()); - } - - private static String createLastLoginIntervalMessage(long lastLogin) { - final long diff = System.currentTimeMillis() - lastLogin; - return (int) (diff / 86400000) + " days " - + (int) (diff / 3600000 % 24) + " hours " - + (int) (diff / 60000 % 60) + " mins " - + (int) (diff / 1000 % 60) + " secs"; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java deleted file mode 100644 index 860ae73d..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeBannedPlayersCommand.java +++ /dev/null @@ -1,38 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.task.purge.PurgeService; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -/** - * Command for purging data of banned players. Depending on the settings - * it purges (deletes) data from third-party plugins as well. - */ -public class PurgeBannedPlayersCommand implements ExecutableCommand { - - @Inject - private PurgeService purgeService; - - @Inject - private BukkitService bukkitService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Get the list of banned players - Set bannedPlayers = bukkitService.getBannedPlayers(); - Set namedBanned = new HashSet<>(bannedPlayers.size()); - for (OfflinePlayer offlinePlayer : bannedPlayers) { - namedBanned.add(offlinePlayer.getName().toLowerCase(Locale.ROOT)); - } - - purgeService.purgePlayers(sender, namedBanned, bannedPlayers.toArray(new OfflinePlayer[bannedPlayers.size()])); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java deleted file mode 100644 index 1538061e..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import com.google.common.primitives.Ints; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.task.purge.PurgeService; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Calendar; -import java.util.List; - -/** - * Command for purging the data of players which have not been online for a given number - * of days. Depending on the settings, this removes player data in third-party plugins as well. - */ -public class PurgeCommand implements ExecutableCommand { - - private static final int MINIMUM_LAST_SEEN_DAYS = 30; - - @Inject - private PurgeService purgeService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Get the days parameter - String daysStr = arguments.get(0); - - // Convert the days string to an integer value, and make sure it's valid - Integer days = Ints.tryParse(daysStr); - if (days == null) { - sender.sendMessage(ChatColor.RED + "The value you've entered is invalid!"); - return; - } - - // Validate the value - if (days < MINIMUM_LAST_SEEN_DAYS) { - sender.sendMessage(ChatColor.RED + "You can only purge data older than " - + MINIMUM_LAST_SEEN_DAYS + " days"); - return; - } - - // Create a calender instance to determine the date - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DATE, -days); - long until = calendar.getTimeInMillis(); - - // Run the purge - purgeService.runPurge(sender, until); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java deleted file mode 100644 index 4e20b031..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Removes the stored last position of a user or of all. - */ -public class PurgeLastPositionCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0); - - if ("*".equals(playerName)) { - for (PlayerAuth auth : dataSource.getAllAuths()) { - resetLastPosition(auth); - dataSource.updateQuitLoc(auth); - // TODO: send an update when a messaging service will be implemented (QUITLOC) - } - sender.sendMessage("All players last position locations are now reset"); - } else { - // Get the user auth and make sure the user exists - PlayerAuth auth = dataSource.getAuth(playerName); - if (auth == null) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - return; - } - - resetLastPosition(auth); - dataSource.updateQuitLoc(auth); - // TODO: send an update when a messaging service will be implemented (QUITLOC) - sender.sendMessage(playerName + "'s last position location is now reset"); - } - } - - private static void resetLastPosition(PlayerAuth auth) { - auth.setQuitLocX(0d); - auth.setQuitLocY(0d); - auth.setQuitLocZ(0d); - auth.setWorld("world"); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java deleted file mode 100644 index e0bf9040..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgePlayerCommand.java +++ /dev/null @@ -1,47 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.task.purge.PurgeExecutor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -import static java.util.Collections.singletonList; - -/** - * Command to purge a player. - */ -public class PurgePlayerCommand implements ExecutableCommand { - - @Inject - private PurgeExecutor purgeExecutor; - - @Inject - private BukkitService bukkitService; - - @Inject - private DataSource dataSource; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String option = arguments.size() > 1 ? arguments.get(1) : null; - bukkitService.runTaskAsynchronously( - () -> executeCommand(sender, arguments.get(0), option)); - } - - private void executeCommand(CommandSender sender, String name, String option) { - if ("force".equals(option) || !dataSource.isAuthAvailable(name)) { - OfflinePlayer offlinePlayer = bukkitService.getOfflinePlayer(name); - purgeExecutor.executePurge(singletonList(offlinePlayer), singletonList(name.toLowerCase(Locale.ROOT))); - sender.sendMessage("Purged data for player " + name); - } else { - sender.sendMessage("This player is still registered! Are you sure you want to proceed? " - + "Use '/authme purgeplayer " + name + " force' to run the command anyway"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java deleted file mode 100644 index 3ae185e3..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.List; - -import static java.time.Instant.ofEpochMilli; - -/** - * Command showing the most recent logged in players. - */ -public class RecentPlayersCommand implements ExecutableCommand { - - /** DateTime formatter, producing Strings such as "10:42 AM, 11 Jul". */ - private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("hh:mm a, dd MMM"); - - @Inject - private DataSource dataSource; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - List recentPlayers = dataSource.getRecentlyLoggedInPlayers(); - - sender.sendMessage(ChatColor.BLUE + "[AuthMe] Recently logged in players"); - for (PlayerAuth auth : recentPlayers) { - sender.sendMessage(formatPlayerMessage(auth)); - } - } - - @VisibleForTesting - ZoneId getZoneId() { - return ZoneId.systemDefault(); - } - - private String formatPlayerMessage(PlayerAuth auth) { - String lastLoginText; - if (auth.getLastLogin() == null) { - lastLoginText = "never"; - } else { - LocalDateTime lastLogin = LocalDateTime.ofInstant(ofEpochMilli(auth.getLastLogin()), getZoneId()); - lastLoginText = DATE_FORMAT.format(lastLogin); - } - - return "- " + auth.getRealName() + " (" + lastLoginText + " with IP " + auth.getLastIp() + ")"; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java deleted file mode 100644 index 7b2847f7..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java +++ /dev/null @@ -1,86 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.ValidationService.ValidationResult; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -/** - * Admin command to register a user. - */ -public class RegisterAdminCommand implements ExecutableCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(RegisterAdminCommand.class); - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private CommonService commonService; - - @Inject - private DataSource dataSource; - - @Inject - private BukkitService bukkitService; - - @Inject - private ValidationService validationService; - - @Override - public void executeCommand(final CommandSender sender, List arguments) { - // Get the player name and password - final String playerName = arguments.get(0); - final String playerPass = arguments.get(1); - final String playerNameLowerCase = playerName.toLowerCase(Locale.ROOT); - - // Command logic - ValidationResult passwordValidation = validationService.validatePassword(playerPass, playerName); - if (passwordValidation.hasError()) { - commonService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs()); - return; - } - - bukkitService.runTaskOptionallyAsync(() -> { - if (dataSource.isAuthAvailable(playerNameLowerCase)) { - commonService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); - return; - } - HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase); - PlayerAuth auth = PlayerAuth.builder() - .name(playerNameLowerCase) - .realName(playerName) - .password(hashedPassword) - .registrationDate(System.currentTimeMillis()) - .build(); - - if (!dataSource.saveAuth(auth)) { - commonService.send(sender, MessageKey.ERROR); - return; - } - - commonService.send(sender, MessageKey.REGISTER_SUCCESS); - logger.info(sender.getName() + " registered " + playerName); - final Player player = bukkitService.getPlayerExact(playerName); - if (player != null) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> - // AuthMeReReloaded - Folia compatibility - bukkitService.runTaskIfFolia(player, () -> player.kickPlayer(commonService.retrieveSingleMessage(player, MessageKey.KICK_FOR_ADMIN_REGISTER)))); - } - }); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java deleted file mode 100644 index 2956a39f..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java +++ /dev/null @@ -1,77 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import ch.jalu.injector.factory.SingletonStore; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SettingsWarner; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.Utils; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * The reload command. - */ -public class ReloadCommand implements ExecutableCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ReloadCommand.class); - - @Inject - private AuthMe plugin; - - @Inject - private Settings settings; - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private SettingsWarner settingsWarner; - - @Inject - private SingletonStore reloadableStore; - - @Inject - private SingletonStore settingsDependentStore; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - try { - settings.reload(); - ConsoleLoggerFactory.reloadSettings(settings); - settingsWarner.logWarningsForMisconfigurations(); - - // 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())) { - Utils.logAndSendMessage(sender, "Note: cannot change database type during /authme reload"); - } - performReloadOnServices(); - commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); - } catch (Exception e) { - sender.sendMessage("Error occurred during reload of AuthMe: aborting"); - logger.logException("Aborting! Encountered exception during reload of AuthMe:", e); - plugin.stopOrUnload(); - } - } - - private void performReloadOnServices() { - reloadableStore.retrieveAllOfType() - .forEach(r -> r.reload()); - - settingsDependentStore.retrieveAllOfType() - .forEach(s -> s.reload(settings)); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java deleted file mode 100644 index 51890edc..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Admin command for setting an email to an account. - */ -public class SetEmailCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private PlayerCache playerCache; - - @Inject - private BukkitService bukkitService; - - @Inject - private ValidationService validationService; - - @Override - public void executeCommand(final CommandSender sender, List arguments) { - // Get the player name and email address - final String playerName = arguments.get(0); - final String playerEmail = arguments.get(1); - - // Validate the email address - if (!validationService.validateEmail(playerEmail)) { - commonService.send(sender, MessageKey.INVALID_EMAIL); - return; - } - - bukkitService.runTaskOptionallyAsync(() -> { // AuthMeReReloaded - Folia compatibility - // Validate the user - PlayerAuth auth = dataSource.getAuth(playerName); - if (auth == null) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - return; - } else if (!validationService.isEmailFreeForRegistration(playerEmail, sender)) { - commonService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR); - return; - } - - // Set the email address - auth.setEmail(playerEmail); - if (!dataSource.updateEmail(auth)) { - commonService.send(sender, MessageKey.ERROR); - return; - } - - // Update the player cache - if (playerCache.getAuth(playerName) != null) { - playerCache.updatePlayer(auth); - } - - // Show a status message - commonService.send(sender, MessageKey.EMAIL_CHANGED_SUCCESS); - }); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommand.java deleted file mode 100644 index 899a1103..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetFirstSpawnCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.settings.SpawnLoader; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -public class SetFirstSpawnCommand extends PlayerCommand { - - @Inject - private SpawnLoader spawnLoader; - - @Override - public void runCommand(Player player, List arguments) { - if (spawnLoader.setFirstSpawn(player.getLocation())) { - player.sendMessage("[AuthMe] Correctly defined new first spawn point"); - } else { - player.sendMessage("[AuthMe] SetFirstSpawn has failed, please retry"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetSpawnCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetSpawnCommand.java deleted file mode 100644 index fc9a67b9..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetSpawnCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.settings.SpawnLoader; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -public class SetSpawnCommand extends PlayerCommand { - - @Inject - private SpawnLoader spawnLoader; - - @Override - public void runCommand(Player player, List arguments) { - if (spawnLoader.setSpawn(player.getLocation())) { - player.sendMessage("[AuthMe] Correctly defined new spawn point"); - } else { - player.sendMessage("[AuthMe] SetSpawn has failed, please retry"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SpawnCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SpawnCommand.java deleted file mode 100644 index 92ad0a30..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SpawnCommand.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.util.TeleportUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -public class SpawnCommand extends PlayerCommand { - - @Inject - private SpawnLoader spawnLoader; - @Inject - private BukkitService bukkitService; - - @Override - public void runCommand(Player player, List arguments) { - if (spawnLoader.getSpawn() == null) { - player.sendMessage("[AuthMe] Spawn has failed, please try to define the spawn"); - } else { - bukkitService.runTaskIfFolia(player, () -> TeleportUtils.teleport(player, spawnLoader.getSpawn())); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java deleted file mode 100644 index 1e72c058..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SwitchAntiBotCommand.java +++ /dev/null @@ -1,52 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.command.FoundCommandResult; -import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.service.AntiBotService; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Arrays; -import java.util.List; - -/** - * Display or change the status of the antibot mod. - */ -public class SwitchAntiBotCommand implements ExecutableCommand { - - @Inject - private AntiBotService antiBotService; - - @Inject - private CommandMapper commandMapper; - - @Inject - private HelpProvider helpProvider; - - @Override - public void executeCommand(final CommandSender sender, List arguments) { - if (arguments.isEmpty()) { - sender.sendMessage("[AuthMe] AntiBot status: " + antiBotService.getAntiBotStatus().name()); - return; - } - - String newState = arguments.get(0); - - // Enable or disable the mod - if ("ON".equalsIgnoreCase(newState)) { - antiBotService.overrideAntiBotStatus(true); - sender.sendMessage("[AuthMe] AntiBot Manual Override: enabled!"); - } else if ("OFF".equalsIgnoreCase(newState)) { - antiBotService.overrideAntiBotStatus(false); - sender.sendMessage("[AuthMe] AntiBot Manual Override: disabled!"); - } else { - sender.sendMessage(ChatColor.DARK_RED + "Invalid AntiBot mode!"); - FoundCommandResult result = commandMapper.mapPartsToCommand(sender, Arrays.asList("authme", "antibot")); - helpProvider.outputHelp(sender, result, HelpProvider.SHOW_ARGUMENTS); - sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/authme help antibot"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/TotpDisableAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/TotpDisableAdminCommand.java deleted file mode 100644 index 4789e043..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/TotpDisableAdminCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command to disable two-factor authentication for a user. - */ -public class TotpDisableAdminCommand implements ExecutableCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TotpDisableAdminCommand.class); - - @Inject - private DataSource dataSource; - - @Inject - private Messages messages; - - @Inject - private BukkitService bukkitService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String player = arguments.get(0); - - PlayerAuth auth = dataSource.getAuth(player); - if (auth == null) { - messages.send(sender, MessageKey.UNKNOWN_USER); - } else if (auth.getTotpKey() == null) { - sender.sendMessage(ChatColor.RED + "Player '" + player + "' does not have two-factor auth enabled"); - } else { - removeTotpKey(sender, player); - } - } - - private void removeTotpKey(CommandSender sender, String player) { - if (dataSource.removeTotpKey(player)) { - sender.sendMessage("Disabled two-factor authentication successfully for '" + player + "'"); - logger.info(sender.getName() + " disable two-factor authentication for '" + player + "'"); - - Player onlinePlayer = bukkitService.getPlayerExact(player); - if (onlinePlayer != null) { - messages.send(onlinePlayer, MessageKey.TWO_FACTOR_REMOVED_SUCCESS); - } - } else { - messages.send(sender, MessageKey.ERROR); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/TotpViewStatusCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/TotpViewStatusCommand.java deleted file mode 100644 index d9b2c92c..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/TotpViewStatusCommand.java +++ /dev/null @@ -1,38 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command to see whether a user has enabled two-factor authentication. - */ -public class TotpViewStatusCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private Messages messages; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - String player = arguments.get(0); - - PlayerAuth auth = dataSource.getAuth(player); - if (auth == null) { - messages.send(sender, MessageKey.UNKNOWN_USER); - } else if (auth.getTotpKey() == null) { - sender.sendMessage(ChatColor.RED + "Player '" + player + "' does NOT have two-factor auth enabled"); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Player '" + player + "' has enabled two-factor authentication"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java deleted file mode 100644 index d8901994..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Admin command to unregister a player. - */ -public class UnregisterAdminCommand implements ExecutableCommand { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private BukkitService bukkitService; - - @Inject - private Management management; - - UnregisterAdminCommand() { - } - - @Override - public void executeCommand(final CommandSender sender, List arguments) { - String playerName = arguments.get(0); - - // Make sure the user exists - if (!dataSource.isAuthAvailable(playerName)) { - commonService.send(sender, MessageKey.UNKNOWN_USER); - return; - } - - // Get the player from the server and perform unregister - Player target = bukkitService.getPlayerExact(playerName); - management.performUnregisterByAdmin(sender, playerName, target); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UpdateHelpMessagesCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UpdateHelpMessagesCommand.java deleted file mode 100644 index 7f61afd0..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UpdateHelpMessagesCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.command.help.HelpMessagesService; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.HelpTranslationGenerator; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * Messages command, updates the user's help messages file with any missing files - * from the provided file in the JAR. - */ -public class UpdateHelpMessagesCommand implements ExecutableCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(UpdateHelpMessagesCommand.class); - - @Inject - private HelpTranslationGenerator helpTranslationGenerator; - @Inject - private HelpMessagesService helpMessagesService; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - try { - File updatedFile = helpTranslationGenerator.updateHelpFile(); - sender.sendMessage("Successfully updated the help file '" + updatedFile.getName() + "'"); - helpMessagesService.reloadMessagesFile(); - } catch (IOException e) { - sender.sendMessage("Could not update help file: " + e.getMessage()); - logger.logException("Could not update help file:", e); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java deleted file mode 100644 index 2f7e8a7c..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java +++ /dev/null @@ -1,99 +0,0 @@ -package fr.xephi.authme.command.executable.authme; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Date; -import java.util.List; - -public class VersionCommand implements ExecutableCommand { - - @Inject - private BukkitService bukkitService; - @Inject - private Settings settings; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - // Show some version info - sender.sendMessage(ChatColor.GOLD + "==========[ " + AuthMe.getPluginName() + " ABOUT ]=========="); - sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName() - + " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")"); - sender.sendMessage(ChatColor.GOLD + "Database Implementation: " + ChatColor.WHITE + settings.getProperty(DatabaseSettings.BACKEND).toString()); - sender.sendMessage(ChatColor.GOLD + "Authors:"); - Collection onlinePlayers = bukkitService.getOnlinePlayers(); - printDeveloper(sender, "Gabriele C.", "sgdc3", "Project manager, Contributor", onlinePlayers); - printDeveloper(sender, "Lucas J.", "ljacqu", "Main Developer", onlinePlayers); - printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers); - printDeveloper(sender, "Hex3l", "Hex3l", "Developer", onlinePlayers); - printDeveloper(sender, "krusic22", "krusic22", "Support", onlinePlayers); - sender.sendMessage(ChatColor.GOLD + "Retired authors:"); - printDeveloper(sender, "Alexandre Vanhecke", "xephi59", "Original Author", onlinePlayers); - printDeveloper(sender, "Gnat008", "gnat008", "Developer, Retired", onlinePlayers); - printDeveloper(sender, "DNx5", "DNx5", "Developer, Retired", onlinePlayers); - printDeveloper(sender, "Tim Visee", "timvisee", "Developer, Retired", onlinePlayers); - sender.sendMessage(ChatColor.GOLD + "Website: " + ChatColor.WHITE - + "https://github.com/AuthMe/AuthMeReloaded"); - sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0" - + ChatColor.GRAY + ChatColor.ITALIC + " (See LICENSE file)"); - sender.sendMessage(ChatColor.GOLD + "Copyright: " + ChatColor.WHITE - + "Copyright (c) AuthMe-Team " + new SimpleDateFormat("yyyy").format(new Date()) - + ". Released under GPL v3 License."); - } - - /** - * Print a developer with proper styling. - * - * @param sender The command sender - * @param name The display name of the developer - * @param minecraftName The Minecraft username of the developer, if available - * @param function The function of the developer - * @param onlinePlayers The list of online players - */ - private static void printDeveloper(CommandSender sender, String name, String minecraftName, String function, - Collection onlinePlayers) { - // Print the name - StringBuilder msg = new StringBuilder(); - msg.append(" ") - .append(ChatColor.WHITE) - .append(name); - - // Append the Minecraft name - msg.append(ChatColor.GRAY).append(" // ").append(ChatColor.WHITE).append(minecraftName); - msg.append(ChatColor.GRAY).append(ChatColor.ITALIC).append(" (").append(function).append(")"); - - // Show the online status - if (isPlayerOnline(minecraftName, onlinePlayers)) { - msg.append(ChatColor.GREEN).append(ChatColor.ITALIC).append(" (In-Game)"); - } - - // Print the message - sender.sendMessage(msg.toString()); - } - - /** - * Check whether a player is online. - * - * @param minecraftName The Minecraft player name - * @param onlinePlayers List of online players - * - * @return True if the player is online, false otherwise - */ - private static boolean isPlayerOnline(String minecraftName, Collection onlinePlayers) { - for (Player player : onlinePlayers) { - if (player.getName().equalsIgnoreCase(minecraftName)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/CountryLookup.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/CountryLookup.java deleted file mode 100644 index 78cee462..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/CountryLookup.java +++ /dev/null @@ -1,88 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.service.GeoIpService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.properties.ProtectionSettings; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.regex.Pattern; - -/** - * Shows the GeoIP information as returned by the geoIpService. - */ -class CountryLookup implements DebugSection { - - private static final Pattern IS_IP_ADDR = Pattern.compile("(\\d{1,3}\\.){3}\\d{1,3}"); - - @Inject - private GeoIpService geoIpService; - - @Inject - private DataSource dataSource; - - @Inject - private ValidationService validationService; - - @Override - public String getName() { - return "cty"; - } - - @Override - public String getDescription() { - return "Check country protection / country data"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe country lookup"); - if (arguments.isEmpty()) { - sender.sendMessage("Check player: /authme debug cty Bobby"); - sender.sendMessage("Check IP address: /authme debug cty 127.123.45.67"); - return; - } - - String argument = arguments.get(0); - if (IS_IP_ADDR.matcher(argument).matches()) { - outputInfoForIpAddr(sender, argument); - } else { - outputInfoForPlayer(sender, argument); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.COUNTRY_LOOKUP; - } - - private void outputInfoForIpAddr(CommandSender sender, String ipAddr) { - sender.sendMessage("IP '" + ipAddr + "' maps to country '" + geoIpService.getCountryCode(ipAddr) - + "' (" + geoIpService.getCountryName(ipAddr) + ")"); - if (validationService.isCountryAdmitted(ipAddr)) { - sender.sendMessage(ChatColor.DARK_GREEN + "This IP address' country is not blocked"); - } else { - sender.sendMessage(ChatColor.DARK_RED + "This IP address' country is blocked from the server"); - } - sender.sendMessage("Note: if " + ProtectionSettings.ENABLE_PROTECTION + " is false no country is blocked"); - } - - // TODO #1366: Extend with registration IP? - private void outputInfoForPlayer(CommandSender sender, String name) { - PlayerAuth auth = dataSource.getAuth(name); - if (auth == null) { - sender.sendMessage("No player with name '" + name + "'"); - } else if (auth.getLastIp() == null) { - sender.sendMessage("No last IP address known for '" + name + "'"); - } else { - sender.sendMessage("Player '" + name + "' has IP address " + auth.getLastIp()); - outputInfoForIpAddr(sender, auth.getLastIp()); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java deleted file mode 100644 index 406ee17d..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java +++ /dev/null @@ -1,81 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import ch.jalu.injector.factory.SingletonStore; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.CacheDataSource; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.Map; - -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.applyToLimboPlayersMap; - -/** - * Fetches various statistics, particularly regarding in-memory data that is stored. - */ -class DataStatistics implements DebugSection { - - @Inject - private PlayerCache playerCache; - - @Inject - private LimboService limboService; - - @Inject - private DataSource dataSource; - - @Inject - private SingletonStore singletonStore; - - @Override - public String getName() { - return "stats"; - } - - @Override - public String getDescription() { - return "Outputs general data statistics"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe statistics"); - sender.sendMessage("LimboPlayers in memory: " + applyToLimboPlayersMap(limboService, Map::size)); - sender.sendMessage("PlayerCache size: " + playerCache.getLogged() + " (= logged in players)"); - - outputDatabaseStats(sender); - outputInjectorStats(sender); - sender.sendMessage("Total logger instances: " + ConsoleLoggerFactory.getTotalLoggers()); - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.DATA_STATISTICS; - } - - private void outputDatabaseStats(CommandSender sender) { - sender.sendMessage("Total players in DB: " + dataSource.getAccountsRegistered()); - if (dataSource instanceof CacheDataSource) { - CacheDataSource cacheDataSource = (CacheDataSource) this.dataSource; - sender.sendMessage("Cached PlayerAuth objects: " + cacheDataSource.getCachedAuths().size()); - } - } - - private void outputInjectorStats(CommandSender sender) { - sender.sendMessage("Singleton Java classes: " + singletonStore.retrieveAllOfType().size()); - sender.sendMessage(String.format("(Reloadable: %d / SettingsDependent: %d / HasCleanup: %d)", - singletonStore.retrieveAllOfType(Reloadable.class).size(), - singletonStore.retrieveAllOfType(SettingsDependent.class).size(), - singletonStore.retrieveAllOfType(HasCleanup.class).size())); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java deleted file mode 100644 index 4198a19e..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import ch.jalu.injector.factory.Factory; -import com.google.common.collect.ImmutableSet; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.permission.PermissionsManager; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -/** - * Debug command main. - */ -public class DebugCommand implements ExecutableCommand { - - private static final Set> SECTION_CLASSES = ImmutableSet.of( - PermissionGroups.class, DataStatistics.class, CountryLookup.class, PlayerAuthViewer.class, InputValidator.class, - LimboPlayerViewer.class, CountryLookup.class, HasPermissionChecker.class, TestEmailSender.class, - SpawnLocationViewer.class, MySqlDefaultChanger.class); - - @Inject - private Factory debugSectionFactory; - - @Inject - private PermissionsManager permissionsManager; - - private Map sections; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - DebugSection debugSection = findDebugSection(arguments); - if (debugSection == null) { - sendAvailableSections(sender); - } else { - executeSection(debugSection, sender, arguments); - } - } - - private DebugSection findDebugSection(List arguments) { - if (arguments.isEmpty()) { - return null; - } - return getSections().get(arguments.get(0).toLowerCase(Locale.ROOT)); - } - - private void sendAvailableSections(CommandSender sender) { - sender.sendMessage(ChatColor.BLUE + "AuthMe debug utils"); - sender.sendMessage("Sections available to you:"); - long availableSections = getSections().values().stream() - .filter(section -> permissionsManager.hasPermission(sender, section.getRequiredPermission())) - .peek(e -> sender.sendMessage("- " + e.getName() + ": " + e.getDescription())) - .count(); - - if (availableSections == 0) { - sender.sendMessage(ChatColor.RED + "You don't have permission to view any debug section"); - } - } - - private void executeSection(DebugSection section, CommandSender sender, List arguments) { - if (permissionsManager.hasPermission(sender, section.getRequiredPermission())) { - section.execute(sender, arguments.subList(1, arguments.size())); - } else { - sender.sendMessage(ChatColor.RED + "You don't have permission for this section. See /authme debug"); - } - } - - // Lazy getter - private Map getSections() { - if (sections == null) { - Map sections = new TreeMap<>(); - for (Class sectionClass : SECTION_CLASSES) { - DebugSection section = debugSectionFactory.newInstance(sectionClass); - sections.put(section.getName(), section); - } - this.sections = sections; - } - return sections; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSection.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSection.java deleted file mode 100644 index 155520c4..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSection.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.permission.PermissionNode; -import org.bukkit.command.CommandSender; - -import java.util.List; - -/** - * A debug section: "child" command of the debug command. - */ -interface DebugSection { - - /** - * @return the name to get to this child command - */ - String getName(); - - /** - * @return short description of the child command - */ - String getDescription(); - - /** - * Executes the debug child command. - * - * @param sender the sender executing the command - * @param arguments the arguments, without the label of the child command - */ - void execute(CommandSender sender, List arguments); - - /** - * @return permission required to run this section - */ - PermissionNode getRequiredPermission(); - -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionUtils.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionUtils.java deleted file mode 100644 index fa4200a0..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.CacheDataSource; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.Location; - -import java.lang.reflect.Field; -import java.math.RoundingMode; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; -import java.util.Map; -import java.util.function.Function; - -/** - * Utilities used within the DebugSection implementations. - */ -final class DebugSectionUtils { - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(DebugSectionUtils.class); - private static Field limboEntriesField; - - private DebugSectionUtils() { - } - - /** - * Formats the given location in a human readable way. Null-safe. - * - * @param location the location to format - * @return the formatted location - */ - static String formatLocation(Location location) { - if (location == null) { - return "null"; - } - - String worldName = location.getWorld() == null ? "null" : location.getWorld().getName(); - return formatLocation(location.getX(), location.getY(), location.getZ(), worldName); - } - - /** - * Formats the given location in a human readable way. - * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param world the world name - * @return the formatted location - */ - static String formatLocation(double x, double y, double z, String world) { - return "(" + round(x) + ", " + round(y) + ", " + round(z) + ") in '" + world + "'"; - } - - /** - * Rounds the given number to two decimals. - * - * @param number the number to round - * @return the rounded number - */ - private static String round(double number) { - DecimalFormat df = new DecimalFormat("#.##"); - df.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.US)); - df.setRoundingMode(RoundingMode.HALF_UP); - return df.format(number); - } - - private static Field getLimboPlayerEntriesField() { - if (limboEntriesField == null) { - try { - Field field = LimboService.class.getDeclaredField("entries"); - field.setAccessible(true); - limboEntriesField = field; - } catch (Exception e) { - logger.logException("Could not retrieve LimboService entries field:", e); - } - } - return limboEntriesField; - } - - /** - * Applies the given function to the map in LimboService containing the LimboPlayers. - * As we don't want to expose this information in non-debug settings, this is done with reflection. - * Exceptions are generously caught and {@code null} is returned on failure. - * - * @param limboService the limbo service instance to get the map from - * @param function the function to apply to the map - * @param the result type of the function - * - * @return the value of the function applied to the map, or null upon error - */ - static U applyToLimboPlayersMap(LimboService limboService, Function function) { - Field limboPlayerEntriesField = getLimboPlayerEntriesField(); - if (limboPlayerEntriesField != null) { - try { - return function.apply((Map) limboEntriesField.get(limboService)); - } catch (Exception e) { - logger.logException("Could not retrieve LimboService values:", e); - } - } - return null; - } - - static T castToTypeOrNull(Object object, Class clazz) { - return clazz.isInstance(object) ? clazz.cast(object) : null; - } - - /** - * Unwraps the "cache data source" and returns the underlying source. Returns the - * same as the input argument otherwise. - * - * @param dataSource the data source to unwrap if applicable - * @return the non-cache data source - */ - static DataSource unwrapSourceFromCacheDataSource(DataSource dataSource) { - if (dataSource instanceof CacheDataSource) { - try { - Field source = CacheDataSource.class.getDeclaredField("source"); - source.setAccessible(true); - return (DataSource) source.get(dataSource); - } catch (NoSuchFieldException | IllegalAccessException e) { - logger.logException("Could not get source of CacheDataSource:", e); - return null; - } - } - return dataSource; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/HasPermissionChecker.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/HasPermissionChecker.java deleted file mode 100644 index e8a15b79..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/HasPermissionChecker.java +++ /dev/null @@ -1,138 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import com.google.common.collect.ImmutableList; -import fr.xephi.authme.permission.AdminPermission; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.DefaultPermission; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.function.BiFunction; - -/** - * Checks if a player has a given permission, as checked by AuthMe. - */ -class HasPermissionChecker implements DebugSection { - - static final List> PERMISSION_NODE_CLASSES = ImmutableList.of( - AdminPermission.class, PlayerPermission.class, PlayerStatePermission.class, DebugSectionPermissions.class); - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private BukkitService bukkitService; - - @Override - public String getName() { - return "perm"; - } - - @Override - public String getDescription() { - return "Checks if a player has a given permission"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe permission check"); - if (arguments.size() < 2) { - sender.sendMessage("Check if a player has permission:"); - sender.sendMessage("Example: /authme debug perm bobby my.perm.node"); - sender.sendMessage("Permission system type used: " + permissionsManager.getPermissionSystem()); - return; - } - - final String playerName = arguments.get(0); - final String permissionNode = arguments.get(1); - - Player player = bukkitService.getPlayerExact(playerName); - if (player == null) { - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName); - if (offlinePlayer == null) { - sender.sendMessage(ChatColor.DARK_RED + "Player '" + playerName + "' does not exist"); - } else { - sender.sendMessage("Player '" + playerName + "' not online; checking with offline player"); - performPermissionCheck(offlinePlayer, permissionNode, permissionsManager::hasPermissionOffline, sender); - } - } else { - performPermissionCheck(player, permissionNode, permissionsManager::hasPermission, sender); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.HAS_PERMISSION_CHECK; - } - - /** - * Performs a permission check and informs the given sender of the result. {@code permissionChecker} is the - * permission check to perform with the given {@code node} and the {@code player}. - * - * @param player the player to check a permission for - * @param node the node of the permission to check - * @param permissionChecker permission checking function - * @param sender the sender to inform of the result - * @param

the player type - */ - private static

void performPermissionCheck( - P player, String node, BiFunction permissionChecker, CommandSender sender) { - - PermissionNode permNode = getPermissionNode(sender, node); - if (permissionChecker.apply(player, permNode)) { - sender.sendMessage(ChatColor.DARK_GREEN + "Success: player '" + player.getName() - + "' has permission '" + node + "'"); - } else { - sender.sendMessage(ChatColor.DARK_RED + "Check failed: player '" + player.getName() - + "' does NOT have permission '" + node + "'"); - } - } - - /** - * Based on the given permission node (String), tries to find the according AuthMe {@link PermissionNode} - * instance, or creates a new one if not available. - * - * @param sender the sender (used to inform him if no AuthMe PermissionNode can be matched) - * @param node the node to search for - * @return the node as {@link PermissionNode} object - */ - private static PermissionNode getPermissionNode(CommandSender sender, String node) { - Optional permNode = PERMISSION_NODE_CLASSES.stream() - .map(Class::getEnumConstants) - .flatMap(Arrays::stream) - .filter(perm -> perm.getNode().equals(node)) - .findFirst(); - if (permNode.isPresent()) { - return permNode.get(); - } else { - sender.sendMessage("Did not detect AuthMe permission; using default permission = DENIED"); - return createPermNode(node); - } - } - - private static PermissionNode createPermNode(String node) { - return new PermissionNode() { - @Override - public String getNode() { - return node; - } - - @Override - public DefaultPermission getDefaultPermission() { - return DefaultPermission.NOT_ALLOWED; - } - }; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java deleted file mode 100644 index 2e82c3c8..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/InputValidator.java +++ /dev/null @@ -1,124 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.listener.FailedVerificationException; -import fr.xephi.authme.listener.OnJoinVerifier; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.ValidationService.ValidationResult; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Arrays; -import java.util.List; - -import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.MAIL; -import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.NAME; -import static fr.xephi.authme.command.executable.authme.debug.InputValidator.ValidationObject.PASS; - -/** - * Checks if a sample username, email or password is valid according to the AuthMe settings. - */ -class InputValidator implements DebugSection { - - @Inject - private ValidationService validationService; - - @Inject - private Messages messages; - - @Inject - private OnJoinVerifier onJoinVerifier; - - - @Override - public String getName() { - return "valid"; - } - - @Override - public String getDescription() { - return "Checks if your config.yml allows a password / email"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - if (arguments.size() < 2 || !ValidationObject.matchesAny(arguments.get(0))) { - displayUsageHint(sender); - - } else if (PASS.matches(arguments.get(0))) { - validatePassword(sender, arguments.get(1)); - - } else if (MAIL.matches(arguments.get(0))) { - validateEmail(sender, arguments.get(1)); - - } else if (NAME.matches(arguments.get(0))) { - validateUsername(sender, arguments.get(1)); - - } else { - throw new IllegalStateException("Unexpected validation object with arg[0] = '" + arguments.get(0) + "'"); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.INPUT_VALIDATOR; - } - - private void displayUsageHint(CommandSender sender) { - sender.sendMessage(ChatColor.BLUE + "Validation tests"); - sender.sendMessage("You can define forbidden emails and passwords in your config.yml." - + " You can test your settings with this command."); - final String command = ChatColor.GOLD + "/authme debug valid"; - sender.sendMessage(" Use " + command + " pass " + ChatColor.RESET + " to check a password"); - sender.sendMessage(" Use " + command + " mail " + ChatColor.RESET + " to check an email"); - sender.sendMessage(" Use " + command + " name " + ChatColor.RESET + " to check a username"); - } - - private void validatePassword(CommandSender sender, String password) { - ValidationResult validationResult = validationService.validatePassword(password, ""); - sender.sendMessage(ChatColor.BLUE + "Validation of password '" + password + "'"); - if (validationResult.hasError()) { - messages.send(sender, validationResult.getMessageKey(), validationResult.getArgs()); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Valid password!"); - } - } - - private void validateEmail(CommandSender sender, String email) { - boolean isValidEmail = validationService.validateEmail(email); - sender.sendMessage(ChatColor.BLUE + "Validation of email '" + email + "'"); - if (isValidEmail) { - sender.sendMessage(ChatColor.DARK_GREEN + "Valid email!"); - } else { - sender.sendMessage(ChatColor.DARK_RED + "Email is not valid!"); - } - } - - private void validateUsername(CommandSender sender, String username) { - sender.sendMessage(ChatColor.BLUE + "Validation of username '" + username + "'"); - try { - onJoinVerifier.checkIsValidName(username); - sender.sendMessage("Valid username!"); - } catch (FailedVerificationException failedVerificationEx) { - messages.send(sender, failedVerificationEx.getReason(), failedVerificationEx.getArgs()); - } - } - - - enum ValidationObject { - - PASS, MAIL, NAME; - - static boolean matchesAny(String arg) { - return Arrays.stream(values()).anyMatch(vo -> vo.matches(arg)); - } - - boolean matches(String arg) { - return name().equalsIgnoreCase(arg); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java deleted file mode 100644 index 7338c868..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/LimboPlayerViewer.java +++ /dev/null @@ -1,143 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.data.limbo.persistence.LimboPersistence; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.applyToLimboPlayersMap; -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation; - -/** - * Shows the data stored in LimboPlayers and the equivalent properties on online players. - */ -class LimboPlayerViewer implements DebugSection { - - @Inject - private LimboService limboService; - - @Inject - private LimboPersistence limboPersistence; - - @Inject - private BukkitService bukkitService; - - @Inject - private PermissionsManager permissionsManager; - - @Override - public String getName() { - return "limbo"; - } - - @Override - public String getDescription() { - return "View LimboPlayers and player's \"limbo stats\""; - } - - @Override - public void execute(CommandSender sender, List arguments) { - if (arguments.isEmpty()) { - sender.sendMessage(ChatColor.BLUE + "AuthMe limbo viewer"); - sender.sendMessage("/authme debug limbo : show a player's limbo info"); - sender.sendMessage("Available limbo records: " + applyToLimboPlayersMap(limboService, Map::keySet)); - return; - } - - LimboPlayer memoryLimbo = limboService.getLimboPlayer(arguments.get(0)); - Player player = bukkitService.getPlayerExact(arguments.get(0)); - LimboPlayer diskLimbo = player != null ? limboPersistence.getLimboPlayer(player) : null; - if (memoryLimbo == null && player == null) { - sender.sendMessage(ChatColor.BLUE + "No AuthMe limbo data"); - sender.sendMessage("No limbo data and no player online with name '" + arguments.get(0) + "'"); - return; - } - - sender.sendMessage(ChatColor.BLUE + "Player / limbo / disk limbo info for '" + arguments.get(0) + "'"); - new InfoDisplayer(sender, player, memoryLimbo, diskLimbo) - .sendEntry("Is op", Player::isOp, LimboPlayer::isOperator) - .sendEntry("Walk speed", Player::getWalkSpeed, LimboPlayer::getWalkSpeed) - .sendEntry("Can fly", Player::getAllowFlight, LimboPlayer::isCanFly) - .sendEntry("Fly speed", Player::getFlySpeed, LimboPlayer::getFlySpeed) - .sendEntry("Location", p -> formatLocation(p.getLocation()), l -> formatLocation(l.getLocation())) - .sendEntry("Prim. group", - p -> permissionsManager.hasGroupSupport() ? permissionsManager.getPrimaryGroup(p) : "N/A", - LimboPlayer::getGroups); - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.LIMBO_PLAYER_VIEWER; - } - - /** - * Displays the info for the given LimboPlayer and Player to the provided CommandSender. - */ - private static final class InfoDisplayer { - private final CommandSender sender; - private final Optional player; - private final Optional memoryLimbo; - private final Optional diskLimbo; - - /** - * Constructor. - * - * @param sender command sender to send the information to - * @param player the player to get data from - * @param memoryLimbo the limbo player to get data from - */ - InfoDisplayer(CommandSender sender, Player player, LimboPlayer memoryLimbo, LimboPlayer diskLimbo) { - this.sender = sender; - this.player = Optional.ofNullable(player); - this.memoryLimbo = Optional.ofNullable(memoryLimbo); - this.diskLimbo = Optional.ofNullable(diskLimbo); - - if (memoryLimbo == null) { - sender.sendMessage("Note: no Limbo information available"); - } - if (player == null) { - sender.sendMessage("Note: player is not online"); - } else if (diskLimbo == null) { - sender.sendMessage("Note: no Limbo on disk available"); - } - } - - /** - * Displays a piece of information to the command sender. - * - * @param title the designation of the piece of information - * @param playerGetter getter for data retrieval on Player - * @param limboGetter getter for data retrieval on the LimboPlayer - * @param the data type - * @return this instance (for chaining) - */ - InfoDisplayer sendEntry(String title, - Function playerGetter, - Function limboGetter) { - sender.sendMessage( - title + ": " - + getData(player, playerGetter) - + " / " - + getData(memoryLimbo, limboGetter) - + " / " - + getData(diskLimbo, limboGetter)); - return this; - } - - static String getData(Optional entity, Function getter) { - return entity.map(getter).map(String::valueOf).orElse(" -- "); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/MySqlDefaultChanger.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/MySqlDefaultChanger.java deleted file mode 100644 index d4eb1d3c..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/MySqlDefaultChanger.java +++ /dev/null @@ -1,327 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import ch.jalu.configme.properties.Property; -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.MySQL; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.castToTypeOrNull; -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.unwrapSourceFromCacheDataSource; -import static fr.xephi.authme.data.auth.PlayerAuth.DB_EMAIL_DEFAULT; -import static fr.xephi.authme.data.auth.PlayerAuth.DB_LAST_IP_DEFAULT; -import static fr.xephi.authme.data.auth.PlayerAuth.DB_LAST_LOGIN_DEFAULT; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.getColumnDefaultValue; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.isNotNullColumn; -import static java.lang.String.format; - -/** - * Convenience command to add or remove the default value of a column and its nullable status - * in the MySQL data source. - */ -class MySqlDefaultChanger implements DebugSection { - - private static final String NOT_NULL_SUFFIX = ChatColor.DARK_AQUA + "@" + ChatColor.RESET; - private static final String DEFAULT_VALUE_SUFFIX = ChatColor.GOLD + "#" + ChatColor.RESET; - - private ConsoleLogger logger = ConsoleLoggerFactory.get(MySqlDefaultChanger.class); - - @Inject - private Settings settings; - - @Inject - private DataSource dataSource; - - private MySQL mySql; - - @PostConstruct - void setMySqlField() { - this.mySql = castToTypeOrNull(unwrapSourceFromCacheDataSource(this.dataSource), MySQL.class); - } - - @Override - public String getName() { - return "mysqldef"; - } - - @Override - public String getDescription() { - return "Add or remove the default value of MySQL columns"; - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.MYSQL_DEFAULT_CHANGER; - } - - @Override - public void execute(CommandSender sender, List arguments) { - if (mySql == null) { - sender.sendMessage("Defaults can be changed for the MySQL data source only."); - return; - } - - Operation operation = matchToEnum(arguments, 0, Operation.class); - Columns column = matchToEnum(arguments, 1, Columns.class); - if (operation == Operation.DETAILS) { - showColumnDetails(sender); - } else if (operation == null || column == null) { - displayUsageHints(sender); - } else { - sender.sendMessage(ChatColor.BLUE + "[AuthMe] MySQL change '" + column + "'"); - try (Connection con = getConnection(mySql)) { - switch (operation) { - case ADD: - changeColumnToNotNullWithDefault(sender, column, con); - break; - case REMOVE: - removeNotNullAndDefault(sender, column, con); - break; - default: - throw new IllegalStateException("Unknown operation '" + operation + "'"); - } - } catch (SQLException | IllegalStateException e) { - logger.logException("Failed to perform MySQL default altering operation:", e); - } - } - } - - /** - * Adds a default value to the column definition and adds a {@code NOT NULL} constraint for - * the specified column. - * - * @param sender the command sender initiation the action - * @param column the column to modify - * @param con connection to the database - * @throws SQLException . - */ - private void changeColumnToNotNullWithDefault(CommandSender sender, Columns column, - Connection con) throws SQLException { - final String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - final String columnName = settings.getProperty(column.getColumnNameProperty()); - - // Replace NULLs with future default value - String sql = format("UPDATE %s SET %s = ? WHERE %s IS NULL;", tableName, columnName, columnName); - int updatedRows; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setObject(1, column.getDefaultValue()); - updatedRows = pst.executeUpdate(); - } - sender.sendMessage("Replaced NULLs with default value ('" + column.getDefaultValue() - + "'), modifying " + updatedRows + " entries"); - - // Change column definition to NOT NULL version - try (Statement st = con.createStatement()) { - st.execute(format("ALTER TABLE %s MODIFY %s %s", tableName, columnName, column.getNotNullDefinition())); - sender.sendMessage("Changed column '" + columnName + "' to have NOT NULL constraint"); - } - - // Log success message - logger.info("Changed MySQL column '" + columnName + "' to be NOT NULL, as initiated by '" - + sender.getName() + "'"); - } - - /** - * Removes the {@code NOT NULL} constraint of a column definition and replaces rows with the - * default value to {@code NULL}. - * - * @param sender the command sender initiation the action - * @param column the column to modify - * @param con connection to the database - * @throws SQLException . - */ - private void removeNotNullAndDefault(CommandSender sender, Columns column, Connection con) throws SQLException { - final String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - final String columnName = settings.getProperty(column.getColumnNameProperty()); - - // Change column definition to nullable version - try (Statement st = con.createStatement()) { - st.execute(format("ALTER TABLE %s MODIFY %s %s", tableName, columnName, column.getNullableDefinition())); - sender.sendMessage("Changed column '" + columnName + "' to allow nulls"); - } - - // Replace old default value with NULL - String sql = format("UPDATE %s SET %s = NULL WHERE %s = ?;", tableName, columnName, columnName); - int updatedRows; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setObject(1, column.getDefaultValue()); - updatedRows = pst.executeUpdate(); - } - sender.sendMessage("Replaced default value ('" + column.getDefaultValue() - + "') to be NULL, modifying " + updatedRows + " entries"); - - // Log success message - logger.info("Changed MySQL column '" + columnName + "' to allow NULL, as initiated by '" - + sender.getName() + "'"); - } - - /** - * Outputs the current definitions of all {@link Columns} which can be migrated. - * - * @param sender command sender to output the data to - */ - private void showColumnDetails(CommandSender sender) { - sender.sendMessage(ChatColor.BLUE + "MySQL column details"); - final String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - try (Connection con = getConnection(mySql)) { - final DatabaseMetaData metaData = con.getMetaData(); - for (Columns col : Columns.values()) { - String columnName = settings.getProperty(col.getColumnNameProperty()); - String isNullText = isNotNullColumn(metaData, tableName, columnName) ? "NOT NULL" : "nullable"; - Object defaultValue = getColumnDefaultValue(metaData, tableName, columnName); - String defaultText = defaultValue == null ? "no default" : "default: '" + defaultValue + "'"; - sender.sendMessage(formatColumnWithMetadata(col, metaData, tableName) - + " (" + columnName + "): " + isNullText + ", " + defaultText); - } - } catch (SQLException e) { - logger.logException("Failed while showing column details:", e); - sender.sendMessage("Failed while showing column details. See log for info"); - } - - } - - /** - * Displays sample commands and the list of columns that can be changed. - * - * @param sender the sender issuing the command - */ - private void displayUsageHints(CommandSender sender) { - sender.sendMessage(ChatColor.BLUE + "MySQL column changer"); - sender.sendMessage("Adds or removes a NOT NULL constraint for a column."); - sender.sendMessage("Examples: add a NOT NULL constraint with"); - sender.sendMessage(" /authme debug mysqldef add "); - sender.sendMessage("Remove one with /authme debug mysqldef remove "); - - sender.sendMessage("Available columns: " + constructColumnListWithMetadata()); - sender.sendMessage(" " + NOT_NULL_SUFFIX + ": not-null, " + DEFAULT_VALUE_SUFFIX - + ": has default. See /authme debug mysqldef details"); - } - - /** - * @return list of {@link Columns} we can toggle with suffixes indicating their NOT NULL and default value status - */ - private String constructColumnListWithMetadata() { - try (Connection con = getConnection(mySql)) { - final DatabaseMetaData metaData = con.getMetaData(); - final String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - - List formattedColumns = new ArrayList<>(Columns.values().length); - for (Columns col : Columns.values()) { - formattedColumns.add(formatColumnWithMetadata(col, metaData, tableName)); - } - return String.join(ChatColor.RESET + ", ", formattedColumns); - } catch (SQLException e) { - logger.logException("Failed to construct column list:", e); - return ChatColor.RED + "An error occurred! Please see the console for details."; - } - } - - private String formatColumnWithMetadata(Columns column, DatabaseMetaData metaData, - String tableName) throws SQLException { - String columnName = settings.getProperty(column.getColumnNameProperty()); - boolean isNotNull = isNotNullColumn(metaData, tableName, columnName); - boolean hasDefaultValue = getColumnDefaultValue(metaData, tableName, columnName) != null; - return column.name() - + (isNotNull ? NOT_NULL_SUFFIX : "") - + (hasDefaultValue ? DEFAULT_VALUE_SUFFIX : ""); - } - - /** - * Gets the Connection object from the MySQL data source. - * - * @param mySql the MySQL data source to get the connection from - * @return the connection - */ - @VisibleForTesting - Connection getConnection(MySQL mySql) { - try { - Method method = MySQL.class.getDeclaredMethod("getConnection"); - method.setAccessible(true); - return (Connection) method.invoke(mySql); - } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalStateException("Could not get MySQL connection", e); - } - } - - private static > E matchToEnum(List arguments, int index, Class clazz) { - if (arguments.size() <= index) { - return null; - } - String str = arguments.get(index); - return Arrays.stream(clazz.getEnumConstants()) - .filter(e -> e.name().equalsIgnoreCase(str)) - .findFirst().orElse(null); - } - - private enum Operation { - ADD, REMOVE, DETAILS - } - - /** MySQL columns which can be toggled between being NOT NULL and allowing NULL values. */ - enum Columns { - - LASTLOGIN(DatabaseSettings.MYSQL_COL_LASTLOGIN, - "BIGINT", "BIGINT NOT NULL DEFAULT 0", DB_LAST_LOGIN_DEFAULT), - - LASTIP(DatabaseSettings.MYSQL_COL_LAST_IP, - "VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin", - "VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '127.0.0.1'", - DB_LAST_IP_DEFAULT), - - EMAIL(DatabaseSettings.MYSQL_COL_EMAIL, - "VARCHAR(255)", "VARCHAR(255) NOT NULL DEFAULT 'your@email.com'", DB_EMAIL_DEFAULT); - - private final Property columnNameProperty; - private final String nullableDefinition; - private final String notNullDefinition; - private final Object defaultValue; - - Columns(Property columnNameProperty, String nullableDefinition, - String notNullDefinition, Object defaultValue) { - this.columnNameProperty = columnNameProperty; - this.nullableDefinition = nullableDefinition; - this.notNullDefinition = notNullDefinition; - this.defaultValue = defaultValue; - } - - /** @return property defining the column name in the database */ - Property getColumnNameProperty() { - return columnNameProperty; - } - - /** @return SQL definition of the column allowing NULL values */ - String getNullableDefinition() { - return nullableDefinition; - } - - /** @return SQL definition of the column with a NOT NULL constraint */ - String getNotNullDefinition() { - return notNullDefinition; - } - - /** @return the default value used in {@link #notNullDefinition} */ - Object getDefaultValue() { - return defaultValue; - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java deleted file mode 100644 index 4515ca0b..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PermissionGroups.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -import static java.util.stream.Collectors.toList; - -/** - * Outputs the permission groups of a player. - */ -class PermissionGroups implements DebugSection { - - @Inject - private PermissionsManager permissionsManager; - - @Override - public String getName() { - return "groups"; - } - - @Override - public String getDescription() { - return "Show permission groups a player belongs to"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe permission groups"); - String name = arguments.isEmpty() ? sender.getName() : arguments.get(0); - Player player = Bukkit.getPlayer(name); - if (player == null) { - sender.sendMessage("Player " + name + " could not be found"); - } else { - List groupNames = permissionsManager.getGroups(player).stream() - .map(UserGroup::getGroupName) - .collect(toList()); - - sender.sendMessage("Player " + name + " has permission groups: " + String.join(", ", groupNames)); - sender.sendMessage("Primary group is: " + permissionsManager.getGroups(player)); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.PERM_GROUPS; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PlayerAuthViewer.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/PlayerAuthViewer.java deleted file mode 100644 index 99115cfe..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/PlayerAuthViewer.java +++ /dev/null @@ -1,117 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.List; - -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation; - -/** - * Allows to view the data of a PlayerAuth in the database. - */ -class PlayerAuthViewer implements DebugSection { - - @Inject - private DataSource dataSource; - - @Override - public String getName() { - return "db"; - } - - @Override - public String getDescription() { - return "View player's data in the database"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - if (arguments.isEmpty()) { - sender.sendMessage(ChatColor.BLUE + "AuthMe database viewer"); - sender.sendMessage("Enter player name to view his data in the database."); - sender.sendMessage("Example: /authme debug db Bobby"); - return; - } - - PlayerAuth auth = dataSource.getAuth(arguments.get(0)); - if (auth == null) { - sender.sendMessage(ChatColor.BLUE + "AuthMe database viewer"); - sender.sendMessage("No record exists for '" + arguments.get(0) + "'"); - } else { - displayAuthToSender(auth, sender); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.PLAYER_AUTH_VIEWER; - } - - /** - * Outputs the PlayerAuth information to the given sender. - * - * @param auth the PlayerAuth to display - * @param sender the sender to send the messages to - */ - private void displayAuthToSender(PlayerAuth auth, CommandSender sender) { - sender.sendMessage(ChatColor.BLUE + "[AuthMe] Player " + auth.getNickname() + " / " + auth.getRealName()); - sender.sendMessage("Email: " + auth.getEmail() + ". IP: " + auth.getLastIp() + ". Group: " + auth.getGroupId()); - sender.sendMessage("Quit location: " - + formatLocation(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld())); - sender.sendMessage("Last login: " + formatDate(auth.getLastLogin())); - sender.sendMessage("Registration: " + formatDate(auth.getRegistrationDate()) - + " with IP " + auth.getRegistrationIp()); - - HashedPassword hashedPass = auth.getPassword(); - sender.sendMessage("Hash / salt (partial): '" + safeSubstring(hashedPass.getHash(), 6) - + "' / '" + safeSubstring(hashedPass.getSalt(), 4) + "'"); - sender.sendMessage("TOTP code (partial): '" + safeSubstring(auth.getTotpKey(), 3) + "'"); - } - - /** - * Fail-safe substring method. Guarantees not to show the entire String. - * - * @param str the string to transform - * @param length number of characters to show from the start of the String - * @return the first length characters of the string, or half of the string if it is shorter, - * or empty string if the string is null or empty - */ - private static String safeSubstring(String str, int length) { - if (StringUtils.isBlank(str)) { - return ""; - } else if (str.length() < length) { - return str.substring(0, str.length() / 2) + "..."; - } else { - return str.substring(0, length) + "..."; - } - } - - /** - * Formats the given timestamp to a human readable date. - * - * @param timestamp the timestamp to format (nullable) - * @return the formatted timestamp - */ - private static String formatDate(Long timestamp) { - if (timestamp == null) { - return "Not available (null)"; - } else if (timestamp == 0) { - return "Not available (0)"; - } else { - LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()); - return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(date); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java deleted file mode 100644 index 30f756c3..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/SpawnLocationViewer.java +++ /dev/null @@ -1,87 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation; - -/** - * Shows the spawn location that AuthMe is configured to use. - */ -class SpawnLocationViewer implements DebugSection { - - @Inject - private SpawnLoader spawnLoader; - - @Inject - private Settings settings; - - @Inject - private BukkitService bukkitService; - - - @Override - public String getName() { - return "spawn"; - } - - @Override - public String getDescription() { - return "Shows the spawn location that AuthMe will use"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe spawn location viewer"); - if (arguments.isEmpty()) { - showGeneralInfo(sender); - } else if ("?".equals(arguments.get(0))) { - showHelp(sender); - } else { - showPlayerSpawn(sender, arguments.get(0)); - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.SPAWN_LOCATION; - } - - private void showGeneralInfo(CommandSender sender) { - sender.sendMessage("Spawn priority: " - + String.join(", ", settings.getProperty(RestrictionSettings.SPAWN_PRIORITY))); - sender.sendMessage("AuthMe spawn location: " + formatLocation(spawnLoader.getSpawn())); - sender.sendMessage("AuthMe first spawn location: " + formatLocation(spawnLoader.getFirstSpawn())); - sender.sendMessage("AuthMe (first)spawn are only used depending on the configured priority!"); - sender.sendMessage("Use '/authme debug spawn ?' for further help"); - } - - private void showHelp(CommandSender sender) { - sender.sendMessage("Use /authme spawn and /authme firstspawn to teleport to the spawns."); - sender.sendMessage("/authme set(first)spawn sets the (first) spawn to your current location."); - sender.sendMessage("Use /authme debug spawn to view where a player would be teleported to."); - sender.sendMessage("Read more at https://github.com/AuthMe/AuthMeReloaded/wiki/Spawn-Handling"); - } - - private void showPlayerSpawn(CommandSender sender, String playerName) { - Player player = bukkitService.getPlayerExact(playerName); - if (player == null) { - sender.sendMessage("Player '" + playerName + "' is not online!"); - } else { - Location spawn = spawnLoader.getSpawnLocation(player); - sender.sendMessage("Player '" + playerName + "' has spawn location: " + formatLocation(spawn)); - sender.sendMessage("Note: this check excludes the AuthMe firstspawn."); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java deleted file mode 100644 index 388a18af..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/TestEmailSender.java +++ /dev/null @@ -1,125 +0,0 @@ -package fr.xephi.authme.command.executable.authme.debug; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.mail.SendMailSsl; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.DebugSectionPermissions; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Utils; -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; -import org.bukkit.ChatColor; -import org.bukkit.Server; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.List; - -/** - * Sends out a test email. - */ -class TestEmailSender implements DebugSection { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TestEmailSender.class); - - @Inject - private DataSource dataSource; - - @Inject - private SendMailSsl sendMailSsl; - - @Inject - private Server server; - - - @Override - public String getName() { - return "mail"; - } - - @Override - public String getDescription() { - return "Sends out a test email"; - } - - @Override - public void execute(CommandSender sender, List arguments) { - sender.sendMessage(ChatColor.BLUE + "AuthMe test email sender"); - if (!sendMailSsl.hasAllInformation()) { - sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml " - + "for sending emails. Please check your config.yml"); - return; - } - - String email = getEmail(sender, arguments); - - // getEmail() takes care of informing the sender of the error if email == null - if (email != null) { - boolean sendMail = sendTestEmail(email); - if (sendMail) { - sender.sendMessage("Test email sent to " + email + " with success"); - } else { - sender.sendMessage(ChatColor.RED + "Failed to send test mail to " + email + "; please check your logs"); - } - } - } - - @Override - public PermissionNode getRequiredPermission() { - return DebugSectionPermissions.TEST_EMAIL; - } - - /** - * Gets the email address to use based on the sender and the arguments. If the arguments are empty, - * we attempt to retrieve the email from the sender. If there is an argument, we verify that it is - * an email address. - * {@code null} is returned if no email address could be found. This method informs the sender of - * the specific error in such cases. - * - * @param sender the command sender - * @param arguments the provided arguments - * @return the email to use, or null if none found - */ - private String getEmail(CommandSender sender, List arguments) { - if (arguments.isEmpty()) { - DataSourceValue emailResult = dataSource.getEmail(sender.getName()); - if (!emailResult.rowExists()) { - sender.sendMessage(ChatColor.RED + "Please provide an email address, " - + "e.g. /authme debug mail test@example.com"); - return null; - } - final String email = emailResult.getValue(); - if (Utils.isEmailEmpty(email)) { - sender.sendMessage(ChatColor.RED + "No email set for your account!" - + " Please use /authme debug mail "); - return null; - } - return email; - } else { - String email = arguments.get(0); - if (StringUtils.isInsideString('@', email)) { - return email; - } - sender.sendMessage(ChatColor.RED + "Invalid email! Usage: /authme debug mail test@example.com"); - return null; - } - } - - private boolean sendTestEmail(String email) { - HtmlEmail htmlEmail; - try { - htmlEmail = sendMailSsl.initializeMail(email); - } catch (EmailException e) { - logger.logException("Failed to create email for sample email:", e); - return false; - } - - htmlEmail.setSubject("AuthMe test email"); - String message = "Hello there!
This is a sample email sent to you from a Minecraft server (" - + server.getName() + ") via /authme debug mail. If you're seeing this, sending emails should be fine."; - return sendMailSsl.sendEmail(message, htmlEmail); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java deleted file mode 100644 index c486dd04..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java +++ /dev/null @@ -1,86 +0,0 @@ -package fr.xephi.authme.command.executable.captcha; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.captcha.LoginCaptchaManager; -import fr.xephi.authme.data.captcha.RegistrationCaptchaManager; -import fr.xephi.authme.data.limbo.LimboMessageType; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Captcha command, allowing a player to solve a captcha. - */ -public class CaptchaCommand extends PlayerCommand { - - @Inject - private PlayerCache playerCache; - - @Inject - private LoginCaptchaManager loginCaptchaManager; - - @Inject - private RegistrationCaptchaManager registrationCaptchaManager; - - @Inject - private CommonService commonService; - - @Inject - private LimboService limboService; - - @Inject - private DataSource dataSource; - - @Override - public void runCommand(Player player, List arguments) { - final String name = player.getName(); - - if (playerCache.isAuthenticated(name)) { - // No captcha is relevant if the player is logged in - commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - return; - } - - if (loginCaptchaManager.isCaptchaRequired(name)) { - checkLoginCaptcha(player, arguments.get(0)); - } else { - final boolean isPlayerRegistered = dataSource.isAuthAvailable(name); - if (!isPlayerRegistered && registrationCaptchaManager.isCaptchaRequired(name)) { - checkRegisterCaptcha(player, arguments.get(0)); - } else { - MessageKey errorMessage = isPlayerRegistered ? MessageKey.USAGE_LOGIN : MessageKey.USAGE_REGISTER; - commonService.send(player, errorMessage); - } - } - } - - private void checkLoginCaptcha(Player player, String captchaCode) { - final boolean isCorrectCode = loginCaptchaManager.checkCode(player, captchaCode); - if (isCorrectCode) { - commonService.send(player, MessageKey.CAPTCHA_SUCCESS); - commonService.send(player, MessageKey.LOGIN_MESSAGE); - limboService.unmuteMessageTask(player); - } else { - String newCode = loginCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName()); - commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode); - } - } - - private void checkRegisterCaptcha(Player player, String captchaCode) { - final boolean isCorrectCode = registrationCaptchaManager.checkCode(player, captchaCode); - if (isCorrectCode) { - commonService.send(player, MessageKey.REGISTER_CAPTCHA_SUCCESS); - commonService.send(player, MessageKey.REGISTER_MESSAGE); - } else { - String newCode = registrationCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName()); - commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode); - } - limboService.resetMessageTask(player, LimboMessageType.REGISTER); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java deleted file mode 100644 index 83a0e5b2..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.command.executable.changepassword; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.ValidationService.ValidationResult; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -/** - * The command for a player to change his password with. - */ -public class ChangePasswordCommand extends PlayerCommand { - - @Inject - private CommonService commonService; - - @Inject - private PlayerCache playerCache; - - @Inject - private ValidationService validationService; - - @Inject - private Management management; - - @Inject - private VerificationCodeManager codeManager; - - @Override - public void runCommand(Player player, List arguments) { - String name = player.getName().toLowerCase(Locale.ROOT); - - if (!playerCache.isAuthenticated(name)) { - commonService.send(player, MessageKey.NOT_LOGGED_IN); - return; - } - // Check if the user has been verified or not - if (codeManager.isVerificationRequired(player)) { - codeManager.codeExistOrGenerateNew(name); - commonService.send(player, MessageKey.VERIFICATION_CODE_REQUIRED); - return; - } - - String oldPassword = arguments.get(0); - String newPassword = arguments.get(1); - - // Make sure the password is allowed - ValidationResult passwordValidation = validationService.validatePassword(newPassword, name); - if (passwordValidation.hasError()) { - commonService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs()); - return; - } - - management.performPasswordChange(player, oldPassword, newPassword); - } - - @Override - protected String getAlternativeCommand() { - return "/authme password "; - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_CHANGE_PASSWORD; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java deleted file mode 100644 index 87e38104..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java +++ /dev/null @@ -1,40 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.CommonService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for setting an email to an account. - */ -public class AddEmailCommand extends PlayerCommand { - - @Inject - private Management management; - - @Inject - private CommonService commonService; - - @Override - public void runCommand(Player player, List arguments) { - String email = arguments.get(0); - String emailConfirmation = arguments.get(1); - - if (email.equals(emailConfirmation)) { - // Closer inspection of the mail address handled by the async task - management.performAddEmail(player, email); - } else { - commonService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE); - } - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_ADD_EMAIL; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/ChangeEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/ChangeEmailCommand.java deleted file mode 100644 index a6d52e0a..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/ChangeEmailCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.CommonService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Change email command. - */ -public class ChangeEmailCommand extends PlayerCommand { - - @Inject - private Management management; - - @Inject - private CommonService commonService; - - @Inject - private VerificationCodeManager codeManager; - - @Override - public void runCommand(Player player, List arguments) { - final String playerName = player.getName(); - // Check if the user has been verified or not - if (codeManager.isVerificationRequired(player)) { - codeManager.codeExistOrGenerateNew(playerName); - commonService.send(player, MessageKey.VERIFICATION_CODE_REQUIRED); - return; - } - - String playerMailOld = arguments.get(0); - String playerMailNew = arguments.get(1); - management.performChangeEmail(player, playerMailOld, playerMailNew); - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_CHANGE_EMAIL; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/EmailBaseCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/EmailBaseCommand.java deleted file mode 100644 index 0484e218..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/EmailBaseCommand.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.command.FoundCommandResult; -import fr.xephi.authme.command.help.HelpProvider; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Collections; -import java.util.List; - -/** - * Base command for /email, showing information about the child commands. - */ -public class EmailBaseCommand implements ExecutableCommand { - - @Inject - private CommandMapper commandMapper; - - @Inject - private HelpProvider helpProvider; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - FoundCommandResult result = commandMapper.mapPartsToCommand(sender, Collections.singletonList("email")); - helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/EmailSetPasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/EmailSetPasswordCommand.java deleted file mode 100644 index f3979adc..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/EmailSetPasswordCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.PasswordRecoveryService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.ValidationService.ValidationResult; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for changing password following successful recovery. - */ -public class EmailSetPasswordCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(EmailSetPasswordCommand.class); - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private PasswordRecoveryService recoveryService; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private ValidationService validationService; - - @Override - protected void runCommand(Player player, List arguments) { - if (recoveryService.canChangePassword(player)) { - String name = player.getName(); - String password = arguments.get(0); - - ValidationResult result = validationService.validatePassword(password, name); - if (!result.hasError()) { - HashedPassword hashedPassword = passwordSecurity.computeHash(password, name); - dataSource.updatePassword(name, hashedPassword); - recoveryService.removeFromSuccessfulRecovery(player); - logger.info("Player '" + name + "' has changed their password from recovery"); - commonService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS); - } else { - commonService.send(player, result.getMessageKey(), result.getArgs()); - } - } else { - commonService.send(player, MessageKey.CHANGE_PASSWORD_EXPIRED); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/ProcessCodeCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/ProcessCodeCommand.java deleted file mode 100644 index 0883c18f..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/ProcessCodeCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.PasswordRecoveryService; -import fr.xephi.authme.service.RecoveryCodeService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for submitting email recovery code. - */ -public class ProcessCodeCommand extends PlayerCommand { - - @Inject - private CommonService commonService; - - @Inject - private RecoveryCodeService codeService; - - @Inject - private PasswordRecoveryService recoveryService; - - @Override - protected void runCommand(Player player, List arguments) { - String name = player.getName(); - String code = arguments.get(0); - - if (codeService.hasTriesLeft(name)) { - if (codeService.isCodeValid(name, code)) { - commonService.send(player, MessageKey.RECOVERY_CODE_CORRECT); - recoveryService.addSuccessfulRecovery(player); - codeService.removeCode(name); - } else { - commonService.send(player, MessageKey.INCORRECT_RECOVERY_CODE, - Integer.toString(codeService.getTriesLeft(name))); - } - } else { - codeService.removeCode(name); - commonService.send(player, MessageKey.RECOVERY_TRIES_EXCEEDED); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java deleted file mode 100644 index ebb71133..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java +++ /dev/null @@ -1,91 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.PasswordRecoveryService; -import fr.xephi.authme.service.RecoveryCodeService; -import fr.xephi.authme.util.Utils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for password recovery by email. - */ -public class RecoverEmailCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(RecoverEmailCommand.class); - - @Inject - private CommonService commonService; - - @Inject - private DataSource dataSource; - - @Inject - private PlayerCache playerCache; - - @Inject - private EmailService emailService; - - @Inject - private PasswordRecoveryService recoveryService; - - @Inject - private RecoveryCodeService recoveryCodeService; - - @Inject - private BukkitService bukkitService; - - @Override - protected void runCommand(Player player, List arguments) { - final String playerMail = arguments.get(0); - final String playerName = player.getName(); - - if (!emailService.hasAllInformation()) { - logger.warning("Mail API is not set"); - commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); - return; - } - if (playerCache.isAuthenticated(playerName)) { - commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - return; - } - - DataSourceValue emailResult = dataSource.getEmail(playerName); - if (!emailResult.rowExists()) { - commonService.send(player, MessageKey.USAGE_REGISTER); - return; - } - - final String email = emailResult.getValue(); - if (Utils.isEmailEmpty(email) || !email.equalsIgnoreCase(playerMail)) { - commonService.send(player, MessageKey.INVALID_EMAIL); - return; - } - - bukkitService.runTaskAsynchronously(() -> { - if (recoveryCodeService.isRecoveryCodeNeeded()) { - // Recovery code is needed; generate and send one - recoveryService.createAndSendRecoveryCode(player, email); - } else { - // Code not needed, just send them a new password - recoveryService.generateAndSendNewPassword(player, email); - } - }); - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_RECOVER_EMAIL; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java deleted file mode 100644 index 9e204987..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.command.executable.email; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.Utils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Show email command. - */ -public class ShowEmailCommand extends PlayerCommand { - - @Inject - private CommonService commonService; - - @Inject - private PlayerCache playerCache; - - @Override - public void runCommand(Player player, List arguments) { - PlayerAuth auth = playerCache.getAuth(player.getName()); - if (auth != null && !Utils.isEmailEmpty(auth.getEmail())) { - if (commonService.getProperty(SecuritySettings.USE_EMAIL_MASKING)){ - commonService.send(player, MessageKey.EMAIL_SHOW, emailMask(auth.getEmail())); - } else { - commonService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail()); - } - } else { - commonService.send(player, MessageKey.SHOW_NO_EMAIL); - } - } - - private String emailMask(String email){ - String[] frag = email.split("@"); //Split id and domain - int sid = frag[0].length() / 3 + 1; //Define the id view (required length >= 1) - int sdomain = frag[1].length() / 3; //Define the domain view (required length >= 0) - String id = frag[0].substring(0, sid) + "***"; //Build the id - String domain = "***" + frag[1].substring(sdomain); //Build the domain - return id + "@" + domain; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/login/LoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/login/LoginCommand.java deleted file mode 100644 index 57ae8639..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/login/LoginCommand.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.xephi.authme.command.executable.login; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Login command. - */ -public class LoginCommand extends PlayerCommand { - - @Inject - private Management management; - - @Override - public void runCommand(Player player, List arguments) { - String password = arguments.get(0); - management.performLogin(player, password); - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_LOGIN; - } - - @Override - protected String getAlternativeCommand() { - return "/authme forcelogin "; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/logout/LogoutCommand.java b/src/main/java/fr/xephi/authme/command/executable/logout/LogoutCommand.java deleted file mode 100644 index 83b17882..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/logout/LogoutCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.xephi.authme.command.executable.logout; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.process.Management; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Logout command. - */ -public class LogoutCommand extends PlayerCommand { - - @Inject - private Management management; - - @Override - public void runCommand(Player player, List arguments) { - management.performLogout(player); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java deleted file mode 100644 index 29e98333..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java +++ /dev/null @@ -1,222 +0,0 @@ -package fr.xephi.authme.command.executable.register; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.captcha.RegistrationCaptchaManager; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.process.register.RegisterSecondaryArgument; -import fr.xephi.authme.process.register.RegistrationType; -import fr.xephi.authme.process.register.executors.EmailRegisterParams; -import fr.xephi.authme.process.register.executors.PasswordRegisterParams; -import fr.xephi.authme.process.register.executors.RegistrationMethod; -import fr.xephi.authme.process.register.executors.TwoFactorRegisterParams; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -import static fr.xephi.authme.process.register.RegisterSecondaryArgument.CONFIRMATION; -import static fr.xephi.authme.process.register.RegisterSecondaryArgument.EMAIL_MANDATORY; -import static fr.xephi.authme.process.register.RegisterSecondaryArgument.EMAIL_OPTIONAL; -import static fr.xephi.authme.process.register.RegisterSecondaryArgument.NONE; -import static fr.xephi.authme.settings.properties.RegistrationSettings.REGISTER_SECOND_ARGUMENT; - -/** - * Command for /register. - */ -public class RegisterCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(RegisterCommand.class); - - @Inject - private Management management; - - @Inject - private CommonService commonService; - - @Inject - private BukkitService bukkitService; - - @Inject - private DataSource dataSource; - - @Inject - private EmailService emailService; - - @Inject - private ValidationService validationService; - - @Inject - private RegistrationCaptchaManager registrationCaptchaManager; - - @Override - public void runCommand(Player player, List arguments) { - if (!isCaptchaFulfilled(player)) { - return; // isCaptchaFulfilled handles informing the player on failure - } - - if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) { - //for two factor auth we don't need to check the usage - management.performRegister(RegistrationMethod.TWO_FACTOR_REGISTRATION, - TwoFactorRegisterParams.of(player)); - return; - } else if (arguments.size() < 1) { - commonService.send(player, MessageKey.USAGE_REGISTER); - return; - } - - RegistrationType registrationType = commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE); - if (registrationType == RegistrationType.PASSWORD) { - handlePasswordRegistration(player, arguments); - } else if (registrationType == RegistrationType.EMAIL) { - handleEmailRegistration(player, arguments); - } else { - throw new IllegalStateException("Unknown registration type '" + registrationType + "'"); - } - } - - @Override - protected String getAlternativeCommand() { - return "/authme register "; - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_REGISTER; - } - - private boolean isCaptchaFulfilled(Player player) { - if (registrationCaptchaManager.isCaptchaRequired(player.getName())) { - String code = registrationCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName()); - commonService.send(player, MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED, code); - return false; - } - return true; - } - - private void handlePasswordRegistration(Player player, List arguments) { - if (isSecondArgValidForPasswordRegistration(player, arguments)) { - final String password = arguments.get(0); - final String email = getEmailIfAvailable(arguments); - - management.performRegister(RegistrationMethod.PASSWORD_REGISTRATION, - PasswordRegisterParams.of(player, password, email)); - } - } - - private String getEmailIfAvailable(List arguments) { - if (arguments.size() >= 2) { - RegisterSecondaryArgument secondArgType = commonService.getProperty(REGISTER_SECOND_ARGUMENT); - if (secondArgType == EMAIL_MANDATORY || secondArgType == EMAIL_OPTIONAL) { - return arguments.get(1); - } - } - return null; - } - - /** - * Verifies that the second argument is valid (based on the configuration) - * to perform a password registration. The player is informed if the check - * is unsuccessful. - * - * @param player the player to register - * @param arguments the provided arguments - * @return true if valid, false otherwise - */ - private boolean isSecondArgValidForPasswordRegistration(Player player, List arguments) { - RegisterSecondaryArgument secondArgType = commonService.getProperty(REGISTER_SECOND_ARGUMENT); - // cases where args.size < 2 - if (secondArgType == NONE || secondArgType == EMAIL_OPTIONAL && arguments.size() < 2) { - return true; - } else if (arguments.size() < 2) { - commonService.send(player, MessageKey.USAGE_REGISTER); - return false; - } - - if (secondArgType == CONFIRMATION) { - if (arguments.get(0).equals(arguments.get(1))) { - return true; - } else { - commonService.send(player, MessageKey.PASSWORD_MATCH_ERROR); - return false; - } - } else if (secondArgType == EMAIL_MANDATORY || secondArgType == EMAIL_OPTIONAL) { - if (validationService.validateEmail(arguments.get(1))) { - return true; - } else { - commonService.send(player, MessageKey.INVALID_EMAIL); - return false; - } - } else { - throw new IllegalStateException("Unknown secondary argument type '" + secondArgType + "'"); - } - } - - private void handleEmailRegistration(Player player, List arguments) { - if (!emailService.hasAllInformation()) { - commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); - logger.warning("Cannot register player '" + player.getName() + "': no email or password is set " - + "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath()); - return; - } - - final String email = arguments.get(0); - if (!validationService.validateEmail(email)) { - commonService.send(player, MessageKey.INVALID_EMAIL); - } else if (isSecondArgValidForEmailRegistration(player, arguments)) { - management.performRegister(RegistrationMethod.EMAIL_REGISTRATION, - EmailRegisterParams.of(player, email)); - if (commonService.getProperty(RegistrationSettings.UNREGISTER_ON_EMAIL_VERIFICATION_FAILURE) && commonService.getProperty(RegistrationSettings.UNREGISTER_AFTER_MINUTES) > 0) { - bukkitService.runTaskLater(player, () -> { - if (dataSource.getAuth(player.getName()) != null) { - if (dataSource.getAuth(player.getName()).getLastLogin() == null) { - management.performUnregisterByAdmin(null, player.getName(), player); - } - } - }, 60 * 20 * commonService.getProperty(RegistrationSettings.UNREGISTER_AFTER_MINUTES)); - } - } - } - - /** - * Verifies that the second argument is valid (based on the configuration) - * to perform an email registration. The player is informed if the check - * is unsuccessful. - * - * @param player the player to register - * @param arguments the provided arguments - * @return true if valid, false otherwise - */ - private boolean isSecondArgValidForEmailRegistration(Player player, List arguments) { - RegisterSecondaryArgument secondArgType = commonService.getProperty(REGISTER_SECOND_ARGUMENT); - // cases where args.size < 2 - if (secondArgType == NONE || secondArgType == EMAIL_OPTIONAL && arguments.size() < 2) { - return true; - } else if (arguments.size() < 2) { - commonService.send(player, MessageKey.USAGE_REGISTER); - return false; - } - - if (secondArgType == EMAIL_OPTIONAL || secondArgType == EMAIL_MANDATORY || secondArgType == CONFIRMATION) { - if (arguments.get(0).equals(arguments.get(1))) { - return true; - } else { - commonService.send(player, MessageKey.USAGE_REGISTER); - return false; - } - } else { - throw new IllegalStateException("Unknown secondary argument type '" + secondArgType + "'"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/totp/AddTotpCommand.java b/src/main/java/fr/xephi/authme/command/executable/totp/AddTotpCommand.java deleted file mode 100644 index e8a78bd1..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/totp/AddTotpCommand.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.command.executable.totp; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.security.totp.GenerateTotpService; -import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for a player to enable TOTP. - */ -public class AddTotpCommand extends PlayerCommand { - - @Inject - private GenerateTotpService generateTotpService; - - @Inject - private PlayerCache playerCache; - - @Inject - private Messages messages; - - @Override - protected void runCommand(Player player, List arguments) { - PlayerAuth auth = playerCache.getAuth(player.getName()); - if (auth == null) { - messages.send(player, MessageKey.NOT_LOGGED_IN); - } else if (auth.getTotpKey() == null) { - TotpGenerationResult createdTotpInfo = generateTotpService.generateTotpKey(player); - messages.send(player, MessageKey.TWO_FACTOR_CREATE, - createdTotpInfo.getTotpKey(), createdTotpInfo.getAuthenticatorQrCodeUrl()); - messages.send(player, MessageKey.TWO_FACTOR_CREATE_CONFIRMATION_REQUIRED); - } else { - messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/totp/ConfirmTotpCommand.java b/src/main/java/fr/xephi/authme/command/executable/totp/ConfirmTotpCommand.java deleted file mode 100644 index 85d7bc8a..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/totp/ConfirmTotpCommand.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.command.executable.totp; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.totp.GenerateTotpService; -import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command to enable TOTP by supplying the proper code as confirmation. - */ -public class ConfirmTotpCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ConfirmTotpCommand.class); - - @Inject - private GenerateTotpService generateTotpService; - - @Inject - private PlayerCache playerCache; - - @Inject - private DataSource dataSource; - - @Inject - private Messages messages; - - @Override - protected void runCommand(Player player, List arguments) { - PlayerAuth auth = playerCache.getAuth(player.getName()); - if (auth == null) { - messages.send(player, MessageKey.NOT_LOGGED_IN); - } else if (auth.getTotpKey() != null) { - messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED); - } else { - verifyTotpCodeConfirmation(player, auth, arguments.get(0)); - } - } - - private void verifyTotpCodeConfirmation(Player player, PlayerAuth auth, String inputTotpCode) { - final TotpGenerationResult totpDetails = generateTotpService.getGeneratedTotpKey(player); - if (totpDetails == null) { - messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE); - } else { - boolean isCodeValid = generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, inputTotpCode); - if (isCodeValid) { - generateTotpService.removeGenerateTotpKey(player); - insertTotpKeyIntoDatabase(player, auth, totpDetails); - } else { - messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE); - } - } - } - - private void insertTotpKeyIntoDatabase(Player player, PlayerAuth auth, TotpGenerationResult totpDetails) { - if (dataSource.setTotpKey(player.getName(), totpDetails.getTotpKey())) { - messages.send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS); - auth.setTotpKey(totpDetails.getTotpKey()); - playerCache.updatePlayer(auth); - logger.info("Player '" + player.getName() + "' has successfully added a TOTP key to their account"); - } else { - messages.send(player, MessageKey.ERROR); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/totp/RemoveTotpCommand.java b/src/main/java/fr/xephi/authme/command/executable/totp/RemoveTotpCommand.java deleted file mode 100644 index 649f13e4..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/totp/RemoveTotpCommand.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.xephi.authme.command.executable.totp; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.totp.TotpAuthenticator; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for a player to remove 2FA authentication. - */ -public class RemoveTotpCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(RemoveTotpCommand.class); - - @Inject - private DataSource dataSource; - - @Inject - private PlayerCache playerCache; - - @Inject - private TotpAuthenticator totpAuthenticator; - - @Inject - private Messages messages; - - @Override - protected void runCommand(Player player, List arguments) { - PlayerAuth auth = playerCache.getAuth(player.getName()); - if (auth == null) { - messages.send(player, MessageKey.NOT_LOGGED_IN); - } else if (auth.getTotpKey() == null) { - messages.send(player, MessageKey.TWO_FACTOR_NOT_ENABLED_ERROR); - } else { - if (totpAuthenticator.checkCode(auth, arguments.get(0))) { - removeTotpKeyFromDatabase(player, auth); - } else { - messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE); - } - } - } - - private void removeTotpKeyFromDatabase(Player player, PlayerAuth auth) { - if (dataSource.removeTotpKey(auth.getNickname())) { - auth.setTotpKey(null); - playerCache.updatePlayer(auth); - messages.send(player, MessageKey.TWO_FACTOR_REMOVED_SUCCESS); - logger.info("Player '" + player.getName() + "' removed their TOTP key"); - } else { - messages.send(player, MessageKey.ERROR); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/totp/TotpBaseCommand.java b/src/main/java/fr/xephi/authme/command/executable/totp/TotpBaseCommand.java deleted file mode 100644 index 2b170a03..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/totp/TotpBaseCommand.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.command.executable.totp; - -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.command.FoundCommandResult; -import fr.xephi.authme.command.help.HelpProvider; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Collections; -import java.util.List; - -/** - * Base command for /totp. - */ -public class TotpBaseCommand implements ExecutableCommand { - - @Inject - private CommandMapper commandMapper; - - @Inject - private HelpProvider helpProvider; - - @Override - public void executeCommand(CommandSender sender, List arguments) { - FoundCommandResult result = commandMapper.mapPartsToCommand(sender, Collections.singletonList("totp")); - helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN); - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/totp/TotpCodeCommand.java b/src/main/java/fr/xephi/authme/command/executable/totp/TotpCodeCommand.java deleted file mode 100644 index 760b83ec..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/totp/TotpCodeCommand.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.xephi.authme.command.executable.totp; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.data.limbo.LimboPlayerState; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.login.AsynchronousLogin; -import fr.xephi.authme.security.totp.TotpAuthenticator; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * TOTP code command for processing the 2FA code during the login process. - */ -public class TotpCodeCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TotpCodeCommand.class); - - @Inject - private LimboService limboService; - - @Inject - private PlayerCache playerCache; - - @Inject - private Messages messages; - - @Inject - private TotpAuthenticator totpAuthenticator; - - @Inject - private DataSource dataSource; - - @Inject - private AsynchronousLogin asynchronousLogin; - - @Override - protected void runCommand(Player player, List arguments) { - if (playerCache.isAuthenticated(player.getName())) { - messages.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - return; - } - - PlayerAuth auth = dataSource.getAuth(player.getName()); - if (auth == null) { - messages.send(player, MessageKey.REGISTER_MESSAGE); - return; - } - - LimboPlayer limbo = limboService.getLimboPlayer(player.getName()); - if (limbo != null && limbo.getState() == LimboPlayerState.TOTP_REQUIRED) { - processCode(player, auth, arguments.get(0)); - } else { - logger.debug(() -> "Aborting TOTP check for player '" + player.getName() - + "'. Invalid limbo state: " + (limbo == null ? "no limbo" : limbo.getState())); - messages.send(player, MessageKey.LOGIN_MESSAGE); - } - } - - private void processCode(Player player, PlayerAuth auth, String inputCode) { - boolean isCodeValid = totpAuthenticator.checkCode(auth, inputCode); - if (isCodeValid) { - logger.debug("Successfully checked TOTP code for `{0}`", player.getName()); - asynchronousLogin.performLogin(player, auth); - } else { - logger.debug("Input TOTP code was invalid for player `{0}`", player.getName()); - messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE); - } - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java deleted file mode 100644 index 21993f38..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.xephi.authme.command.executable.unregister; - -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.CommonService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Command for a player to unregister himself. - */ -public class UnregisterCommand extends PlayerCommand { - - @Inject - private Management management; - - @Inject - private CommonService commonService; - - @Inject - private PlayerCache playerCache; - - @Inject - private VerificationCodeManager codeManager; - - @Override - public void runCommand(Player player, List arguments) { - String playerPass = arguments.get(0); - String playerName = player.getName(); - - // Make sure the player is authenticated - if (!playerCache.isAuthenticated(playerName)) { - commonService.send(player, MessageKey.NOT_LOGGED_IN); - return; - } - - // Check if the user has been verified or not - if (codeManager.isVerificationRequired(player)) { - codeManager.codeExistOrGenerateNew(playerName); - commonService.send(player, MessageKey.VERIFICATION_CODE_REQUIRED); - return; - } - - // Unregister the player - management.performUnregister(player, playerPass); - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_UNREGISTER; - } - - @Override - protected String getAlternativeCommand() { - return "/authme unregister "; - } -} diff --git a/src/main/java/fr/xephi/authme/command/executable/verification/VerificationCommand.java b/src/main/java/fr/xephi/authme/command/executable/verification/VerificationCommand.java deleted file mode 100644 index dc28c95f..00000000 --- a/src/main/java/fr/xephi/authme/command/executable/verification/VerificationCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.command.executable.verification; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.command.PlayerCommand; -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.CommonService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Used to complete the email verification process. - */ -public class VerificationCommand extends PlayerCommand { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(VerificationCommand.class); - - @Inject - private CommonService commonService; - - @Inject - private VerificationCodeManager codeManager; - - @Override - public void runCommand(Player player, List arguments) { - final String playerName = player.getName(); - - if (!codeManager.canSendMail()) { - logger.warning("Mail API is not set"); - commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); - return; - } - - if (codeManager.isVerificationRequired(player)) { - if (codeManager.isCodeRequired(playerName)) { - if (codeManager.checkCode(playerName, arguments.get(0))) { - commonService.send(player, MessageKey.VERIFICATION_CODE_VERIFIED); - } else { - commonService.send(player, MessageKey.INCORRECT_VERIFICATION_CODE); - } - } else { - commonService.send(player, MessageKey.VERIFICATION_CODE_EXPIRED); - } - } else { - if (codeManager.hasEmail(playerName)) { - commonService.send(player, MessageKey.VERIFICATION_CODE_ALREADY_VERIFIED); - } else { - commonService.send(player, MessageKey.VERIFICATION_CODE_EMAIL_NEEDED); - commonService.send(player, MessageKey.ADD_EMAIL_MESSAGE); - } - } - } - - @Override - public MessageKey getArgumentsMismatchMessage() { - return MessageKey.USAGE_VERIFICATION_CODE; - } -} diff --git a/src/main/java/fr/xephi/authme/command/help/HelpMessage.java b/src/main/java/fr/xephi/authme/command/help/HelpMessage.java deleted file mode 100644 index ae306a40..00000000 --- a/src/main/java/fr/xephi/authme/command/help/HelpMessage.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.command.help; - -/** - * Common, non-generic keys for messages used when showing command help. - * All keys are prefixed with {@code common}. - */ -public enum HelpMessage { - - HEADER("header"), - - OPTIONAL("optional"), - - HAS_PERMISSION("hasPermission"), - - NO_PERMISSION("noPermission"), - - DEFAULT("default"), - - RESULT("result"); - - private static final String PREFIX = "common."; - private final String key; - - /** - * Constructor. - * - * @param key the message key - */ - HelpMessage(String key) { - this.key = PREFIX + key; - } - - /** @return the message key */ - public String getKey() { - return key; - } - - /** @return the key without the common prefix */ - public String getEntryKey() { - // Note ljacqu 20171008: #getKey is called more often than this method, so we optimize for the former method - return key.substring(PREFIX.length()); - } -} diff --git a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java b/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java deleted file mode 100644 index 994d967b..00000000 --- a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java +++ /dev/null @@ -1,117 +0,0 @@ -package fr.xephi.authme.command.help; - -import com.google.common.base.CaseFormat; -import fr.xephi.authme.command.CommandArgumentDescription; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.CommandUtils; -import fr.xephi.authme.message.HelpMessagesFileHandler; -import fr.xephi.authme.permission.DefaultPermission; - -import javax.inject.Inject; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * Manages translatable help messages. - */ -public class HelpMessagesService { - - private static final String COMMAND_PREFIX = "commands."; - private static final String DESCRIPTION_SUFFIX = ".description"; - private static final String DETAILED_DESCRIPTION_SUFFIX = ".detailedDescription"; - private static final String DEFAULT_PERMISSIONS_PATH = "common.defaultPermissions."; - - private final HelpMessagesFileHandler helpMessagesFileHandler; - - @Inject - HelpMessagesService(HelpMessagesFileHandler helpMessagesFileHandler) { - this.helpMessagesFileHandler = helpMessagesFileHandler; - } - - /** - * Creates a copy of the supplied command description with localized messages where present. - * - * @param command the command to build a localized version of - * @return the localized description - */ - public CommandDescription buildLocalizedDescription(CommandDescription command) { - final String path = COMMAND_PREFIX + getCommandSubPath(command); - if (!helpMessagesFileHandler.hasSection(path)) { - // Messages file does not have a section for this command - return the provided command - return command; - } - - CommandDescription.CommandBuilder builder = CommandDescription.builder() - .description(getText(path + DESCRIPTION_SUFFIX, command::getDescription)) - .detailedDescription(getText(path + DETAILED_DESCRIPTION_SUFFIX, command::getDetailedDescription)) - .executableCommand(command.getExecutableCommand()) - .parent(command.getParent()) - .labels(command.getLabels()) - .permission(command.getPermission()); - - int i = 1; - for (CommandArgumentDescription argument : command.getArguments()) { - String argPath = path + ".arg" + i; - String label = getText(argPath + ".label", argument::getName); - String description = getText(argPath + ".description", argument::getDescription); - builder.withArgument(label, description, argument.isOptional()); - ++i; - } - - CommandDescription localCommand = builder.build(); - localCommand.getChildren().addAll(command.getChildren()); - return localCommand; - } - - public String getDescription(CommandDescription command) { - return getText(COMMAND_PREFIX + getCommandSubPath(command) + DESCRIPTION_SUFFIX, command::getDescription); - } - - public String getMessage(HelpMessage message) { - return helpMessagesFileHandler.getMessage(message.getKey()); - } - - public String getMessage(HelpSection section) { - return helpMessagesFileHandler.getMessage(section.getKey()); - } - - public String getMessage(DefaultPermission defaultPermission) { - // e.g. {default_permissions_path}.opOnly for DefaultPermission.OP_ONLY - String path = DEFAULT_PERMISSIONS_PATH + getDefaultPermissionsSubPath(defaultPermission); - return helpMessagesFileHandler.getMessage(path); - } - - public static String getDefaultPermissionsSubPath(DefaultPermission defaultPermission) { - return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, defaultPermission.name()); - } - - private String getText(String path, Supplier defaultTextGetter) { - String message = helpMessagesFileHandler.getMessageIfExists(path); - return message == null - ? defaultTextGetter.get() - : message; - } - - - /** - * Triggers a reload of the help messages file. Note that this method is not needed - * to be called for /authme reload. - */ - public void reloadMessagesFile() { - helpMessagesFileHandler.reload(); - } - - /** - * Returns the command subpath for the given command (i.e. the path to the translations for the given - * command under "commands"). - * - * @param command the command to process - * @return the subpath for the command's texts - */ - public static String getCommandSubPath(CommandDescription command) { - return CommandUtils.constructParentList(command) - .stream() - .map(cmd -> cmd.getLabels().get(0)) - .collect(Collectors.joining(".")); - } -} diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java deleted file mode 100644 index 4327b827..00000000 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ /dev/null @@ -1,328 +0,0 @@ -package fr.xephi.authme.command.help; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import fr.xephi.authme.command.CommandArgumentDescription; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.CommandUtils; -import fr.xephi.authme.command.FoundCommandResult; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.permission.DefaultPermission; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; - -import static fr.xephi.authme.command.help.HelpSection.DETAILED_DESCRIPTION; -import static fr.xephi.authme.command.help.HelpSection.SHORT_DESCRIPTION; -import static java.util.Collections.singletonList; - -/** - * Help syntax generator for AuthMe commands. - */ -public class HelpProvider implements Reloadable { - - // --- Bit flags --- - /** Set to show a command overview. */ - public static final int SHOW_COMMAND = 0x001; - /** Set to show the description of the command. */ - public static final int SHOW_DESCRIPTION = 0x002; - /** Set to show the detailed description of the command. */ - public static final int SHOW_LONG_DESCRIPTION = 0x004; - /** Set to include the arguments the command takes. */ - public static final int SHOW_ARGUMENTS = 0x008; - /** Set to show the permissions required to execute the command. */ - public static final int SHOW_PERMISSIONS = 0x010; - /** Set to show alternative labels for the command. */ - public static final int SHOW_ALTERNATIVES = 0x020; - /** Set to show the child commands of the command. */ - public static final int SHOW_CHILDREN = 0x040; - - /** Shortcut for setting all options. */ - public static final int ALL_OPTIONS = ~0; - - private final PermissionsManager permissionsManager; - private final HelpMessagesService helpMessagesService; - /** int with bit flags set corresponding to the above constants for enabled sections. */ - private Integer enabledSections; - - @Inject - HelpProvider(PermissionsManager permissionsManager, HelpMessagesService helpMessagesService) { - this.permissionsManager = permissionsManager; - this.helpMessagesService = helpMessagesService; - } - - /** - * Builds the help messages based on the provided arguments. - * - * @param sender the sender to evaluate permissions with - * @param result the command result to create help for - * @param options output options - * @return the generated help messages - */ - private List buildHelpOutput(CommandSender sender, FoundCommandResult result, int options) { - if (result.getCommandDescription() == null) { - return singletonList(ChatColor.DARK_RED + "Failed to retrieve any help information!"); - } - - List lines = new ArrayList<>(); - options = filterDisabledSections(options); - if (options == 0) { - // Return directly if no options are enabled so we don't include the help header - return lines; - } - String header = helpMessagesService.getMessage(HelpMessage.HEADER); - if (!header.isEmpty()) { - lines.add(ChatColor.GOLD + header); - } - - CommandDescription command = helpMessagesService.buildLocalizedDescription(result.getCommandDescription()); - List correctLabels = ImmutableList.copyOf(filterCorrectLabels(command, result.getLabels())); - - if (hasFlag(SHOW_COMMAND, options)) { - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.COMMAND) + ": " - + CommandUtils.buildSyntax(command, correctLabels)); - } - if (hasFlag(SHOW_DESCRIPTION, options)) { - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(SHORT_DESCRIPTION) + ": " - + ChatColor.WHITE + command.getDescription()); - } - if (hasFlag(SHOW_LONG_DESCRIPTION, options)) { - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(DETAILED_DESCRIPTION) + ":"); - lines.add(ChatColor.WHITE + " " + command.getDetailedDescription()); - } - if (hasFlag(SHOW_ARGUMENTS, options)) { - addArgumentsInfo(command, lines); - } - if (hasFlag(SHOW_PERMISSIONS, options) && sender != null) { - addPermissionsInfo(command, sender, lines); - } - if (hasFlag(SHOW_ALTERNATIVES, options)) { - addAlternativesInfo(command, correctLabels, lines); - } - if (hasFlag(SHOW_CHILDREN, options)) { - addChildrenInfo(command, correctLabels, lines); - } - - return lines; - } - - /** - * Outputs 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 - */ - public void outputHelp(CommandSender sender, FoundCommandResult result, int options) { - List lines = buildHelpOutput(sender, result, options); - for (String line : lines) { - sender.sendMessage(line); - } - } - - @Override - public void reload() { - // We don't know about the reloading order of the classes, i.e. we cannot assume that HelpMessagesService - // has already been reloaded. So set the enabledSections flag to null and redefine it first time needed. - enabledSections = null; - } - - /** - * Removes any disabled sections from the options. Sections are considered disabled - * if the translated text for the section is empty. - * - * @param options the options to process - * @return the options without any disabled sections - */ - @SuppressWarnings("checkstyle:BooleanExpressionComplexity") - private int filterDisabledSections(int options) { - if (enabledSections == null) { - enabledSections = flagFor(HelpSection.COMMAND, SHOW_COMMAND) - | flagFor(HelpSection.SHORT_DESCRIPTION, SHOW_DESCRIPTION) - | flagFor(HelpSection.DETAILED_DESCRIPTION, SHOW_LONG_DESCRIPTION) - | flagFor(HelpSection.ARGUMENTS, SHOW_ARGUMENTS) - | flagFor(HelpSection.PERMISSIONS, SHOW_PERMISSIONS) - | flagFor(HelpSection.ALTERNATIVES, SHOW_ALTERNATIVES) - | flagFor(HelpSection.CHILDREN, SHOW_CHILDREN); - } - return options & enabledSections; - } - - private int flagFor(HelpSection section, int flag) { - return helpMessagesService.getMessage(section).isEmpty() ? 0 : flag; - } - - /** - * Adds help info about the given command's arguments into the provided list. - * - * @param command the command to generate arguments info for - * @param lines the output collection to add the info to - */ - private void addArgumentsInfo(CommandDescription command, List lines) { - if (command.getArguments().isEmpty()) { - return; - } - - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.ARGUMENTS) + ":"); - StringBuilder argString = new StringBuilder(); - String optionalText = " (" + helpMessagesService.getMessage(HelpMessage.OPTIONAL) + ")"; - for (CommandArgumentDescription argument : command.getArguments()) { - argString.setLength(0); - argString.append(" ").append(ChatColor.YELLOW).append(ChatColor.ITALIC).append(argument.getName()) - .append(": ").append(ChatColor.WHITE).append(argument.getDescription()); - - if (argument.isOptional()) { - argString.append(ChatColor.GRAY).append(ChatColor.ITALIC).append(optionalText); - } - lines.add(argString.toString()); - } - } - - /** - * Adds help info about the given command's alternative labels into the provided list. - * - * @param command the command for which to generate info about its labels - * @param correctLabels labels used to access the command (sanitized) - * @param lines the output collection to add the info to - */ - private void addAlternativesInfo(CommandDescription command, List correctLabels, List lines) { - if (command.getLabels().size() <= 1) { - return; - } - - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.ALTERNATIVES) + ":"); - - // Label with which the command was called -> don't show it as an alternative - final String usedLabel; - // Takes alternative label and constructs list of labels, e.g. "reg" -> [authme, reg] - final Function> commandLabelsFn; - - if (correctLabels.size() == 1) { - usedLabel = correctLabels.get(0); - commandLabelsFn = label -> singletonList(label); - } else { - usedLabel = correctLabels.get(1); - commandLabelsFn = label -> Arrays.asList(correctLabels.get(0), label); - } - - // Create a list of alternatives - for (String label : command.getLabels()) { - if (!label.equalsIgnoreCase(usedLabel)) { - lines.add(" " + CommandUtils.buildSyntax(command, commandLabelsFn.apply(label))); - } - } - } - - /** - * Adds help info about the given command's permissions into the provided list. - * - * @param command the command to generate permissions info for - * @param sender the command sender, used to evaluate permissions - * @param lines the output collection to add the info to - */ - private void addPermissionsInfo(CommandDescription command, CommandSender sender, List lines) { - PermissionNode permission = command.getPermission(); - if (permission == null) { - return; - } - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.PERMISSIONS) + ":"); - - boolean hasPermission = permissionsManager.hasPermission(sender, permission); - lines.add(String.format(" " + ChatColor.YELLOW + ChatColor.ITALIC + "%s" + ChatColor.GRAY + " (%s)", - permission.getNode(), getLocalPermissionText(hasPermission))); - - // Addendum to the line to specify whether the sender has permission or not when default is OP_ONLY - final DefaultPermission defaultPermission = permission.getDefaultPermission(); - String addendum = ""; - if (DefaultPermission.OP_ONLY.equals(defaultPermission)) { - addendum = " (" + getLocalPermissionText(defaultPermission.evaluate(sender)) + ")"; - } - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpMessage.DEFAULT) + ": " - + ChatColor.GRAY + ChatColor.ITALIC + helpMessagesService.getMessage(defaultPermission) + addendum); - - // Evaluate if the sender has permission to the command - ChatColor permissionColor; - String permissionText; - if (permissionsManager.hasPermission(sender, command.getPermission())) { - permissionColor = ChatColor.GREEN; - permissionText = getLocalPermissionText(true); - } else { - permissionColor = ChatColor.DARK_RED; - permissionText = getLocalPermissionText(false); - } - lines.add(String.format(ChatColor.GOLD + " %s: %s" + ChatColor.ITALIC + "%s", - helpMessagesService.getMessage(HelpMessage.RESULT), permissionColor, permissionText)); - } - - private String getLocalPermissionText(boolean hasPermission) { - if (hasPermission) { - return helpMessagesService.getMessage(HelpMessage.HAS_PERMISSION); - } - return helpMessagesService.getMessage(HelpMessage.NO_PERMISSION); - } - - /** - * Adds help info about the given command's child command into the provided list. - * - * @param command the command for which to generate info about its child commands - * @param correctLabels the labels used to access the given command (sanitized) - * @param lines the output collection to add the info to - */ - private void addChildrenInfo(CommandDescription command, List correctLabels, List lines) { - if (command.getChildren().isEmpty()) { - return; - } - - lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.CHILDREN) + ":"); - String parentCommandPath = String.join(" ", correctLabels); - for (CommandDescription child : command.getChildren()) { - lines.add(" /" + parentCommandPath + " " + child.getLabels().get(0) - + ChatColor.GRAY + ChatColor.ITALIC + ": " + helpMessagesService.getDescription(child)); - } - } - - private static boolean hasFlag(int flag, int options) { - return (flag & options) != 0; - } - - /** - * Returns a list of labels for the given command, using the labels from the provided labels list - * as long as they are correct. - *

- * Background: commands may have multiple labels (e.g. /authme register vs. /authme reg). It is interesting - * for us to keep with which label the user requested the command. At the same time, when a user inputs a - * non-existent label, we try to find the most similar one. This method keeps all labels that exists and will - * default to the command's first label when an invalid label is encountered. - *

- * Examples: - * command = "authme register", labels = {authme, egister}. Output: {authme, register} - * command = "authme register", labels = {authme, reg}. Output: {authme, reg} - * - * @param command the command to compare the labels against - * @param labels the labels as input by the user - * @return list of correct labels, keeping the user's input where possible - */ - @VisibleForTesting - static List filterCorrectLabels(CommandDescription command, List labels) { - List commands = CommandUtils.constructParentList(command); - List correctLabels = new ArrayList<>(); - boolean foundIncorrectLabel = false; - for (int i = 0; i < commands.size(); ++i) { - if (!foundIncorrectLabel && i < labels.size() && commands.get(i).hasLabel(labels.get(i))) { - correctLabels.add(labels.get(i)); - } else { - foundIncorrectLabel = true; - correctLabels.add(commands.get(i).getLabels().get(0)); - } - } - return correctLabels; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/help/HelpSection.java b/src/main/java/fr/xephi/authme/command/help/HelpSection.java deleted file mode 100644 index 506262bf..00000000 --- a/src/main/java/fr/xephi/authme/command/help/HelpSection.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.xephi.authme.command.help; - -/** - * Translatable sections. Message keys are prefixed by {@code section}. - */ -public enum HelpSection { - - COMMAND("command"), - - SHORT_DESCRIPTION("description"), - - DETAILED_DESCRIPTION("detailedDescription"), - - ARGUMENTS("arguments"), - - ALTERNATIVES("alternatives"), - - PERMISSIONS("permissions"), - - CHILDREN("children"); - - private static final String PREFIX = "section."; - private final String key; - - /** - * Constructor. - * - * @param key the message key - */ - HelpSection(String key) { - this.key = PREFIX + key; - } - - /** @return the message key */ - public String getKey() { - return key; - } - - /** @return the key without the common prefix */ - public String getEntryKey() { - // Note ljacqu 20171008: #getKey is called more often than this method, so we optimize for the former method - return key.substring(PREFIX.length()); - } -} diff --git a/src/main/java/fr/xephi/authme/data/ProxySessionManager.java b/src/main/java/fr/xephi/authme/data/ProxySessionManager.java deleted file mode 100644 index d0c60fb2..00000000 --- a/src/main/java/fr/xephi/authme/data/ProxySessionManager.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.xephi.authme.data; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.util.expiring.ExpiringSet; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -public class ProxySessionManager implements HasCleanup { - - private final ExpiringSet activeProxySessions; - - @Inject - public ProxySessionManager() { - long countTimeout = 5; - activeProxySessions = new ExpiringSet<>(countTimeout, TimeUnit.SECONDS); - } - - /** - * Saves the player in the set - * @param name the player's name - */ - private void setActiveSession(String name) { - activeProxySessions.add(name.toLowerCase(Locale.ROOT)); - } - - /** - * Process a proxy session message from AuthMeBungee - * @param name the player to process - */ - public void processProxySessionMessage(String name) { - setActiveSession(name); - } - - /** - * Returns if the player should be logged in or not - * @param name the name of the player to check - * @return true if player has to be logged in, false otherwise - */ - public boolean shouldResumeSession(String name) { - return activeProxySessions.contains(name); - } - - @Override - public void performCleanup() { - activeProxySessions.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/QuickCommandsProtectionManager.java b/src/main/java/fr/xephi/authme/data/QuickCommandsProtectionManager.java deleted file mode 100644 index 7414e21c..00000000 --- a/src/main/java/fr/xephi/authme/data/QuickCommandsProtectionManager.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.data; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.ProtectionSettings; -import fr.xephi.authme.util.expiring.ExpiringSet; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.concurrent.TimeUnit; - -public class QuickCommandsProtectionManager implements SettingsDependent, HasCleanup { - - private final PermissionsManager permissionsManager; - - private final ExpiringSet latestJoin; - - @Inject - public QuickCommandsProtectionManager(Settings settings, PermissionsManager permissionsManager) { - this.permissionsManager = permissionsManager; - long countTimeout = settings.getProperty(ProtectionSettings.QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS); - latestJoin = new ExpiringSet<>(countTimeout, TimeUnit.MILLISECONDS); - reload(settings); - } - - /** - * Save the player in the set - * @param name the player's name - */ - private void setJoin(String name) { - latestJoin.add(name); - } - - /** - * Returns whether the given player has the permission and should be saved in the set - * @param player the player to check - * @return true if the player has the permission, false otherwise - */ - private boolean shouldSavePlayer(Player player) { - return permissionsManager.hasPermission(player, PlayerPermission.QUICK_COMMANDS_PROTECTION); - } - - /** - * Process the player join - * @param player the player to process - */ - public void processJoin(Player player) { - if (shouldSavePlayer(player)) { - setJoin(player.getName()); - } - } - - /** - * Returns whether the given player is able to perform the command - * @param name the name of the player to check - * @return true if the player is not in the set (so it's allowed to perform the command), false otherwise - */ - public boolean isAllowed(String name) { - return !latestJoin.contains(name); - } - - @Override - public void reload(Settings settings) { - long countTimeout = settings.getProperty(ProtectionSettings.QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS); - latestJoin.setExpiration(countTimeout, TimeUnit.MILLISECONDS); - } - - @Override - public void performCleanup() { - latestJoin.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/TempbanManager.java b/src/main/java/fr/xephi/authme/data/TempbanManager.java deleted file mode 100644 index 2a767874..00000000 --- a/src/main/java/fr/xephi/authme/data/TempbanManager.java +++ /dev/null @@ -1,138 +0,0 @@ -package fr.xephi.authme.data; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.expiring.TimedCounter; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE; - -/** - * Manager for handling temporary bans. - */ -public class TempbanManager implements SettingsDependent, HasCleanup { - - private final Map> ipLoginFailureCounts; - private final BukkitService bukkitService; - private final Messages messages; - - private boolean isEnabled; - private int threshold; - private int length; - private long resetThreshold; - private String customCommand; - - @Inject - TempbanManager(BukkitService bukkitService, Messages messages, Settings settings) { - this.ipLoginFailureCounts = new ConcurrentHashMap<>(); - this.bukkitService = bukkitService; - this.messages = messages; - reload(settings); - } - - /** - * Increases the failure count for the given IP address/username combination. - * - * @param address The player's IP address - * @param name The username - */ - public void increaseCount(String address, String name) { - if (isEnabled) { - TimedCounter countsByName = ipLoginFailureCounts.computeIfAbsent( - address, k -> new TimedCounter<>(resetThreshold, TimeUnit.MINUTES)); - countsByName.increment(name); - } - } - - /** - * Set the failure count for a given IP address / username combination to 0. - * - * @param address The IP address - * @param name The username - */ - public void resetCount(String address, String name) { - if (isEnabled) { - TimedCounter counter = ipLoginFailureCounts.get(address); - if (counter != null) { - counter.remove(name); - } - } - } - - /** - * 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) { - TimedCounter countsByName = ipLoginFailureCounts.get(address); - if (countsByName != null) { - return countsByName.total() >= 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 name = player.getName(); - final String ip = PlayerUtils.getPlayerIp(player); - final String reason = messages.retrieveSingle(player, MessageKey.TEMPBAN_MAX_LOGINS); - - final Date expires = new Date(); - long newTime = expires.getTime() + (length * MILLIS_PER_MINUTE); - expires.setTime(newTime); - - bukkitService.runTask(player,() -> { // AuthMeReReloaded - Folia compatibility - if (customCommand.isEmpty()) { - bukkitService.banIp(ip, reason, expires, "AuthMe"); - player.kickPlayer(reason); - } else { - String command = customCommand - .replace("%player%", name) - .replace("%ip%", ip); - bukkitService.dispatchConsoleCommand(command); - } - }); - - ipLoginFailureCounts.remove(ip); - } - } - - @Override - public void reload(Settings 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); - this.resetThreshold = settings.getProperty(SecuritySettings.TEMPBAN_MINUTES_BEFORE_RESET); - this.customCommand = settings.getProperty(SecuritySettings.TEMPBAN_CUSTOM_COMMAND); - } - - @Override - public void performCleanup() { - for (TimedCounter countsByIp : ipLoginFailureCounts.values()) { - countsByIp.removeExpiredEntries(); - } - ipLoginFailureCounts.entrySet().removeIf(e -> e.getValue().isEmpty()); - } -} diff --git a/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java b/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java deleted file mode 100644 index ad1b778d..00000000 --- a/src/main/java/fr/xephi/authme/data/VerificationCodeManager.java +++ /dev/null @@ -1,194 +0,0 @@ -package fr.xephi.authme.data; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.RandomStringUtils; -import fr.xephi.authme.util.Utils; -import fr.xephi.authme.util.expiring.ExpiringMap; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -public class VerificationCodeManager implements SettingsDependent, HasCleanup { - - private final EmailService emailService; - private final DataSource dataSource; - private final PermissionsManager permissionsManager; - - private final ExpiringMap verificationCodes; - private final Set verifiedPlayers; - - private boolean canSendMail; - - @Inject - VerificationCodeManager(Settings settings, DataSource dataSource, EmailService emailService, - PermissionsManager permissionsManager) { - this.emailService = emailService; - this.dataSource = dataSource; - this.permissionsManager = permissionsManager; - verifiedPlayers = new HashSet<>(); - long countTimeout = settings.getProperty(SecuritySettings.VERIFICATION_CODE_EXPIRATION_MINUTES); - verificationCodes = new ExpiringMap<>(countTimeout, TimeUnit.MINUTES); - reload(settings); - } - - /** - * Returns if it is possible to send emails - * - * @return true if the service is enabled, false otherwise - */ - public boolean canSendMail() { - return canSendMail; - } - - /** - * Returns whether the given player is able to verify his identity - * - * @param player the player to verify - * @return true if the player has not been verified yet, false otherwise - */ - public boolean isVerificationRequired(Player player) { - final String name = player.getName(); - return canSendMail - && !isPlayerVerified(name) - && permissionsManager.hasPermission(player, PlayerPermission.VERIFICATION_CODE) - && hasEmail(name); - } - - /** - * Returns whether the given player is required to verify his identity through a command - * - * @param name the name of the player to verify - * @return true if the player has an existing code and has not been verified yet, false otherwise - */ - public boolean isCodeRequired(String name) { - return canSendMail && hasCode(name) && !isPlayerVerified(name); - } - - /** - * Returns whether the given player has been verified or not - * - * @param name the name of the player to verify - * @return true if the player has been verified, false otherwise - */ - private boolean isPlayerVerified(String name) { - return verifiedPlayers.contains(name.toLowerCase(Locale.ROOT)); - } - - /** - * Returns if a code exists for the player - * - * @param name the name of the player to verify - * @return true if the code exists, false otherwise - */ - public boolean hasCode(String name) { - return (verificationCodes.get(name.toLowerCase(Locale.ROOT)) != null); - } - - /** - * Returns whether the given player is able to receive emails - * - * @param name the name of the player to verify - * @return true if the player is able to receive emails, false otherwise - */ - public boolean hasEmail(String name) { - boolean result = false; - DataSourceValue emailResult = dataSource.getEmail(name); - if (emailResult.rowExists()) { - final String email = emailResult.getValue(); - if (!Utils.isEmailEmpty(email)) { - result = true; - } - } - return result; - } - - /** - * Check if a code exists for the player or generates and saves a new one. - * - * @param name the player's name - */ - public void codeExistOrGenerateNew(String name) { - if (!hasCode(name)) { - generateCode(name); - } - } - - /** - * Generates a code for the player and returns it. - * - * @param name the name of the player to generate a code for - */ - private void generateCode(String name) { - DataSourceValue emailResult = dataSource.getEmail(name); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'年'MM'月'dd'日' HH:mm:ss"); - Date date = new Date(System.currentTimeMillis()); - if (emailResult.rowExists()) { - final String email = emailResult.getValue(); - if (!Utils.isEmailEmpty(email)) { - String code = RandomStringUtils.generateNum(6); // 6 digits code - verificationCodes.put(name.toLowerCase(Locale.ROOT), code); - emailService.sendVerificationMail(name, email, code, dateFormat.format(date)); - } - } - } - - /** - * Checks the given code against the existing one. - * - * @param name the name of the player to check - * @param code the supplied code - * @return true if the code matches, false otherwise - */ - public boolean checkCode(String name, String code) { - boolean correct = false; - if (code.equals(verificationCodes.get(name.toLowerCase(Locale.ROOT)))) { - verify(name); - correct = true; - } - return correct; - } - - /** - * Add the user to the set of verified users - * - * @param name the name of the player to generate a code for - */ - public void verify(String name) { - verifiedPlayers.add(name.toLowerCase(Locale.ROOT)); - } - - /** - * Remove the user from the set of verified users - * - * @param name the name of the player to generate a code for - */ - public void unverify(String name){ - verifiedPlayers.remove(name.toLowerCase(Locale.ROOT)); - } - - @Override - public void reload(Settings settings) { - canSendMail = emailService.hasAllInformation(); - long countTimeout = settings.getProperty(SecuritySettings.VERIFICATION_CODE_EXPIRATION_MINUTES); - verificationCodes.setExpiration(countTimeout, TimeUnit.MINUTES); - } - - @Override - public void performCleanup() { - verificationCodes.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java b/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java deleted file mode 100644 index 82082629..00000000 --- a/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java +++ /dev/null @@ -1,373 +0,0 @@ -package fr.xephi.authme.data.auth; - -import fr.xephi.authme.security.crypts.HashedPassword; -import org.bukkit.Location; - -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; - -import static com.google.common.base.Preconditions.checkNotNull; - - -/** - * AuthMe player data. - */ -@SuppressWarnings("checkstyle:FinalClass") // Justification: class is mocked in multiple tests -public class PlayerAuth { - - /** Default email used in the database if the email column is defined to be NOT NULL. */ - public static final String DB_EMAIL_DEFAULT = "your@email.com"; - /** Default last login value used in the database if the last login column is NOT NULL. */ - public static final long DB_LAST_LOGIN_DEFAULT = 0; - /** Default last ip value used in the database if the last IP column is NOT NULL. */ - public static final String DB_LAST_IP_DEFAULT = "127.0.0.1"; - - /** The player's name in lowercase, e.g. "xephi". */ - private String nickname; - /** The player's name in the correct casing, e.g. "Xephi". */ - private String realName; - private HashedPassword password; - private String totpKey; - private String email; - private String lastIp; - private int groupId; - private Long lastLogin; - private String registrationIp; - private long registrationDate; - // Fields storing the player's quit location - private double x; - private double y; - private double z; - private String world; - private float yaw; - private float pitch; - private UUID uuid; - - /** - * Hidden constructor. - * - * @see #builder() - */ - private PlayerAuth() { - } - - - public void setNickname(String nickname) { - this.nickname = nickname.toLowerCase(Locale.ROOT); - } - - public String getNickname() { - return nickname; - } - - public String getRealName() { - return realName; - } - - public void setRealName(String realName) { - this.realName = realName; - } - - public int getGroupId() { - return groupId; - } - - public void setQuitLocation(Location location) { - x = location.getBlockX(); - y = location.getBlockY(); - z = location.getBlockZ(); - world = location.getWorld().getName(); - } - - public double getQuitLocX() { - return x; - } - - public void setQuitLocX(double d) { - this.x = d; - } - - public double getQuitLocY() { - return y; - } - - public void setQuitLocY(double d) { - this.y = d; - } - - public double getQuitLocZ() { - return z; - } - - public void setQuitLocZ(double d) { - this.z = d; - } - - public String getWorld() { - return world; - } - - public void setWorld(String world) { - this.world = world; - } - - public float getYaw() { - return yaw; - } - - public float getPitch() { - return pitch; - } - - public String getLastIp() { - return lastIp; - } - - public void setLastIp(String lastIp) { - this.lastIp = lastIp; - } - - public Long getLastLogin() { - return lastLogin; - } - - public void setLastLogin(long lastLogin) { - this.lastLogin = lastLogin; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public HashedPassword getPassword() { - return password; - } - - public void setPassword(HashedPassword password) { - this.password = password; - } - - public String getRegistrationIp() { - return registrationIp; - } - - public long getRegistrationDate() { - return registrationDate; - } - - public void setRegistrationDate(long registrationDate) { - this.registrationDate = registrationDate; - } - - public String getTotpKey() { - return totpKey; - } - - public void setTotpKey(String totpKey) { - this.totpKey = totpKey; - } - - public UUID getUuid() { - return uuid; - } - - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof PlayerAuth)) { - return false; - } - PlayerAuth other = (PlayerAuth) obj; - return Objects.equals(other.lastIp, this.lastIp) && Objects.equals(other.nickname, this.nickname); - } - - @Override - public int hashCode() { - int hashCode = 7; - hashCode = 71 * hashCode + (this.nickname != null ? this.nickname.hashCode() : 0); - hashCode = 71 * hashCode + (this.lastIp != null ? this.lastIp.hashCode() : 0); - return hashCode; - } - - @Override - public String toString() { - return "Player : " + nickname + " | " + realName - + " ! IP : " + lastIp - + " ! LastLogin : " + lastLogin - + " ! LastPosition : " + x + "," + y + "," + z + "," + world - + " ! Email : " + email - + " ! Password : {" + password.getHash() + ", " + password.getSalt() + "}" - + " ! UUID : " + uuid; - } - - public static Builder builder() { - return new Builder(); - } - - public static final class Builder { - private String name; - private String realName; - private HashedPassword password; - private String totpKey; - private String lastIp; - private String email; - private int groupId = -1; - private Long lastLogin; - private String registrationIp; - private Long registrationDate; - - private double x; - private double y; - private double z; - private String world; - private float yaw; - private float pitch; - private UUID uuid; - - /** - * Creates a PlayerAuth object. - * - * @return the generated PlayerAuth - */ - public PlayerAuth build() { - PlayerAuth auth = new PlayerAuth(); - auth.nickname = checkNotNull(name).toLowerCase(Locale.ROOT); - auth.realName = Optional.ofNullable(realName).orElse("Player"); - auth.password = Optional.ofNullable(password).orElse(new HashedPassword("")); - auth.totpKey = totpKey; - auth.email = DB_EMAIL_DEFAULT.equals(email) ? null : email; - auth.lastIp = lastIp; // Don't check against default value 127.0.0.1 as it may be a legit value - auth.groupId = groupId; - auth.lastLogin = isEqualTo(lastLogin, DB_LAST_LOGIN_DEFAULT) ? null : lastLogin; - auth.registrationIp = registrationIp; - auth.registrationDate = registrationDate == null ? System.currentTimeMillis() : registrationDate; - - auth.x = x; - auth.y = y; - auth.z = z; - auth.world = Optional.ofNullable(world).orElse("world"); - auth.yaw = yaw; - auth.pitch = pitch; - auth.uuid = uuid; - return auth; - } - - private static boolean isEqualTo(Long value, long defaultValue) { - return value != null && defaultValue == value; - } - - public Builder name(String name) { - this.name = name; - return this; - } - - public Builder realName(String realName) { - this.realName = realName; - return this; - } - - public Builder password(HashedPassword password) { - this.password = password; - return this; - } - - public Builder password(String hash, String salt) { - return password(new HashedPassword(hash, salt)); - } - - public Builder totpKey(String totpKey) { - this.totpKey = totpKey; - return this; - } - - public Builder lastIp(String lastIp) { - this.lastIp = lastIp; - return this; - } - - /** - * Sets the location info based on the argument. - * - * @param location the location info to set - * @return this builder instance - */ - public Builder location(Location location) { - this.x = location.getX(); - this.y = location.getY(); - this.z = location.getZ(); - this.world = location.getWorld().getName(); - this.yaw = location.getYaw(); - this.pitch = location.getPitch(); - return this; - } - - public Builder locX(double x) { - this.x = x; - return this; - } - - public Builder locY(double y) { - this.y = y; - return this; - } - - public Builder locZ(double z) { - this.z = z; - return this; - } - - public Builder locWorld(String world) { - this.world = world; - return this; - } - - public Builder locYaw(float yaw) { - this.yaw = yaw; - return this; - } - - public Builder locPitch(float pitch) { - this.pitch = pitch; - return this; - } - - public Builder lastLogin(Long lastLogin) { - this.lastLogin = lastLogin; - return this; - } - - public Builder groupId(int groupId) { - this.groupId = groupId; - return this; - } - - public Builder email(String email) { - this.email = email; - return this; - } - - public Builder registrationIp(String ip) { - this.registrationIp = ip; - return this; - } - - public Builder registrationDate(long date) { - this.registrationDate = date; - return this; - } - - public Builder uuid(UUID uuid) { - this.uuid = uuid; - return this; - } - } -} diff --git a/src/main/java/fr/xephi/authme/data/auth/PlayerCache.java b/src/main/java/fr/xephi/authme/data/auth/PlayerCache.java deleted file mode 100644 index e617f20e..00000000 --- a/src/main/java/fr/xephi/authme/data/auth/PlayerCache.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.data.auth; - - -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Used to manage player's Authenticated status - */ -public class PlayerCache { - - private final Map cache = new ConcurrentHashMap<>(); - - PlayerCache() { - } - - /** - * Adds the given auth object to the player cache (for the name defined in the PlayerAuth). - * - * @param auth the player auth object to save - */ - public void updatePlayer(PlayerAuth auth) { - cache.put(auth.getNickname().toLowerCase(Locale.ROOT), auth); - } - - /** - * Removes a player from the player cache. - * - * @param user name of the player to remove - */ - public void removePlayer(String user) { - cache.remove(user.toLowerCase(Locale.ROOT)); - } - - /** - * Get whether a player is authenticated (i.e. whether he is present in the player cache). - * - * @param user player's name - * - * @return true if player is logged in, false otherwise. - */ - public boolean isAuthenticated(String user) { - return cache.containsKey(user.toLowerCase(Locale.ROOT)); - } - - /** - * Returns the PlayerAuth associated with the given user, if available. - * - * @param user name of the player - * - * @return the associated auth object, or null if not available - */ - public PlayerAuth getAuth(String user) { - return cache.get(user.toLowerCase(Locale.ROOT)); - } - - /** - * @return number of logged in players - */ - public int getLogged() { - return cache.size(); - } - - /** - * Returns the player cache data. - * - * @return all player auths inside the player cache - */ - public Map getCache() { - return this.cache; - } - -} diff --git a/src/main/java/fr/xephi/authme/data/captcha/CaptchaCodeStorage.java b/src/main/java/fr/xephi/authme/data/captcha/CaptchaCodeStorage.java deleted file mode 100644 index 5667a6f1..00000000 --- a/src/main/java/fr/xephi/authme/data/captcha/CaptchaCodeStorage.java +++ /dev/null @@ -1,94 +0,0 @@ -package fr.xephi.authme.data.captcha; - -import fr.xephi.authme.util.RandomStringUtils; -import fr.xephi.authme.util.expiring.ExpiringMap; - -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Primitive service for storing captcha codes. - */ -public class CaptchaCodeStorage { - - /** Map of captcha codes (with player name as key, case-insensitive). */ - private ExpiringMap captchaCodes; - /** Number of characters newly generated captcha codes should have. */ - private int captchaLength; - - /** - * Constructor. - * - * @param expirationInMinutes minutes after which a saved captcha code expires - * @param captchaLength the number of characters a captcha code should have - */ - public CaptchaCodeStorage(long expirationInMinutes, int captchaLength) { - this.captchaCodes = new ExpiringMap<>(expirationInMinutes, TimeUnit.MINUTES); - this.captchaLength = captchaLength; - } - - /** - * Sets the expiration of captcha codes. - * - * @param expirationInMinutes minutes after which a saved captcha code expires - */ - public void setExpirationInMinutes(long expirationInMinutes) { - captchaCodes.setExpiration(expirationInMinutes, TimeUnit.MINUTES); - } - - /** - * Sets the captcha length. - * - * @param captchaLength number of characters a captcha code should have - */ - public void setCaptchaLength(int captchaLength) { - this.captchaLength = captchaLength; - } - - /** - * 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 getCodeOrGenerateNew(String name) { - String code = captchaCodes.get(name.toLowerCase(Locale.ROOT)); - 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 - */ - private String generateCode(String name) { - String code = RandomStringUtils.generate(captchaLength); - captchaCodes.put(name.toLowerCase(Locale.ROOT), code); - return code; - } - - /** - * Checks the given code against the existing one. Upon success, the saved captcha code is removed from storage. - * Upon failure, a new code is generated. - * - * @param name the name of the player to check - * @param code the supplied code - * @return true if the code matches, false otherwise - */ - public boolean checkCode(String name, String code) { - String nameLowerCase = name.toLowerCase(Locale.ROOT); - String savedCode = captchaCodes.get(nameLowerCase); - if (savedCode != null && savedCode.equalsIgnoreCase(code)) { - captchaCodes.remove(nameLowerCase); - return true; - } else { - generateCode(name); - } - return false; - } - - public void removeExpiredEntries() { - captchaCodes.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/captcha/CaptchaManager.java b/src/main/java/fr/xephi/authme/data/captcha/CaptchaManager.java deleted file mode 100644 index c3daeb6c..00000000 --- a/src/main/java/fr/xephi/authme/data/captcha/CaptchaManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package fr.xephi.authme.data.captcha; - -import org.bukkit.entity.Player; - -/** - * Manages captcha codes. - */ -public interface CaptchaManager { - - /** - * Returns whether the given player is required to solve a captcha. - * - * @param name the name of the player to verify - * @return true if the player has to solve a captcha, false otherwise - */ - boolean isCaptchaRequired(String name); - - /** - * 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 - */ - String getCaptchaCodeOrGenerateNew(String name); - - /** - * Checks the given code against the existing one. This method is not reentrant, i.e. it performs additional - * state changes on success or failure, such as modifying some counter or setting a player as verified. - *

- * On success, the code associated with the player is cleared; on failure, a new code is generated. - * - * @param player the player to check - * @param code the supplied code - * @return true if the code matches, false otherwise - */ - boolean checkCode(Player player, String code); - -} diff --git a/src/main/java/fr/xephi/authme/data/captcha/LoginCaptchaManager.java b/src/main/java/fr/xephi/authme/data/captcha/LoginCaptchaManager.java deleted file mode 100644 index 1d97af69..00000000 --- a/src/main/java/fr/xephi/authme/data/captcha/LoginCaptchaManager.java +++ /dev/null @@ -1,95 +0,0 @@ -package fr.xephi.authme.data.captcha; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.expiring.TimedCounter; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Manager for the handling of captchas after too many failed login attempts. - */ -public class LoginCaptchaManager implements CaptchaManager, SettingsDependent, HasCleanup { - - private final TimedCounter playerCounts; - private final CaptchaCodeStorage captchaCodeStorage; - - private boolean isEnabled; - private int threshold; - - @Inject - LoginCaptchaManager(Settings settings) { - // Note: Proper values are set in reload() - this.captchaCodeStorage = new CaptchaCodeStorage(30, 4); - this.playerCounts = new TimedCounter<>(9, TimeUnit.MINUTES); - reload(settings); - } - - /** - * Increases the failure count for the given player. - * - * @param name the player's name - */ - public void increaseLoginFailureCount(String name) { - if (isEnabled) { - String playerLower = name.toLowerCase(Locale.ROOT); - playerCounts.increment(playerLower); - } - } - - @Override - public boolean isCaptchaRequired(String playerName) { - return isEnabled && playerCounts.get(playerName.toLowerCase(Locale.ROOT)) >= threshold; - } - - @Override - public String getCaptchaCodeOrGenerateNew(String name) { - return captchaCodeStorage.getCodeOrGenerateNew(name); - } - - @Override - public boolean checkCode(Player player, String code) { - String nameLower = player.getName().toLowerCase(Locale.ROOT); - boolean isCodeCorrect = captchaCodeStorage.checkCode(nameLower, code); - if (isCodeCorrect) { - playerCounts.remove(nameLower); - } - return isCodeCorrect; - } - - /** - * Resets the login count of the given player to 0. - * - * @param name the player's name - */ - public void resetLoginFailureCount(String name) { - if (isEnabled) { - playerCounts.remove(name.toLowerCase(Locale.ROOT)); - } - } - - @Override - public void reload(Settings settings) { - int expirationInMinutes = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET); - captchaCodeStorage.setExpirationInMinutes(expirationInMinutes); - int captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH); - captchaCodeStorage.setCaptchaLength(captchaLength); - - int countTimeout = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET); - playerCounts.setExpiration(countTimeout, TimeUnit.MINUTES); - - isEnabled = settings.getProperty(SecuritySettings.ENABLE_LOGIN_FAILURE_CAPTCHA); - threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA); - } - - @Override - public void performCleanup() { - playerCounts.removeExpiredEntries(); - captchaCodeStorage.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/captcha/RegistrationCaptchaManager.java b/src/main/java/fr/xephi/authme/data/captcha/RegistrationCaptchaManager.java deleted file mode 100644 index 655d9940..00000000 --- a/src/main/java/fr/xephi/authme/data/captcha/RegistrationCaptchaManager.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.xephi.authme.data.captcha; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.expiring.ExpiringSet; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Captcha manager for registration. - */ -public class RegistrationCaptchaManager implements CaptchaManager, SettingsDependent, HasCleanup { - - private static final int MINUTES_VALID_FOR_REGISTRATION = 30; - - private final ExpiringSet verifiedNamesForRegistration; - private final CaptchaCodeStorage captchaCodeStorage; - private boolean isEnabled; - - @Inject - RegistrationCaptchaManager(Settings settings) { - // NOTE: proper captcha length is set in reload() - this.captchaCodeStorage = new CaptchaCodeStorage(MINUTES_VALID_FOR_REGISTRATION, 4); - this.verifiedNamesForRegistration = new ExpiringSet<>(MINUTES_VALID_FOR_REGISTRATION, TimeUnit.MINUTES); - reload(settings); - } - - @Override - public boolean isCaptchaRequired(String name) { - return isEnabled && !verifiedNamesForRegistration.contains(name.toLowerCase(Locale.ROOT)); - } - - @Override - public String getCaptchaCodeOrGenerateNew(String name) { - return captchaCodeStorage.getCodeOrGenerateNew(name); - } - - @Override - public boolean checkCode(Player player, String code) { - String nameLower = player.getName().toLowerCase(Locale.ROOT); - boolean isCodeCorrect = captchaCodeStorage.checkCode(nameLower, code); - if (isCodeCorrect) { - verifiedNamesForRegistration.add(nameLower); - } - return isCodeCorrect; - } - - @Override - public void reload(Settings settings) { - int captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH); - captchaCodeStorage.setCaptchaLength(captchaLength); - - isEnabled = settings.getProperty(SecuritySettings.ENABLE_CAPTCHA_FOR_REGISTRATION); - } - - @Override - public void performCleanup() { - verifiedNamesForRegistration.removeExpiredEntries(); - captchaCodeStorage.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/AllowFlightRestoreType.java b/src/main/java/fr/xephi/authme/data/limbo/AllowFlightRestoreType.java deleted file mode 100644 index 753650b6..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/AllowFlightRestoreType.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import org.bukkit.entity.Player; - -/** - * Possible types to restore the "allow flight" property - * from LimboPlayer to Bukkit Player. - */ -public enum AllowFlightRestoreType { - - /** Set value from LimboPlayer to Player. */ - RESTORE { - @Override - public void restoreAllowFlight(Player player, LimboPlayer limbo) { - player.setAllowFlight(limbo.isCanFly()); - } - }, - - /** Always set flight enabled to true. */ - ENABLE { - @Override - public void restoreAllowFlight(Player player, LimboPlayer limbo) { - player.setAllowFlight(true); - } - }, - - /** Always set flight enabled to false. */ - DISABLE { - @Override - public void restoreAllowFlight(Player player, LimboPlayer limbo) { - player.setAllowFlight(false); - } - }, - - /** The user's flight handling is not modified. */ - NOTHING { - @Override - public void restoreAllowFlight(Player player, LimboPlayer limbo) { - // noop - } - - @Override - public void processPlayer(Player player) { - // noop - } - }; - - /** - * Restores the "allow flight" property from the LimboPlayer to the Player. - * This method behaves differently for each restoration type. - * - * @param player the player to modify - * @param limbo the limbo player to read from - */ - public abstract void restoreAllowFlight(Player player, LimboPlayer limbo); - - /** - * Processes the player when a LimboPlayer instance is created based on him. Typically this - * method revokes the {@code allowFlight} property to be restored again later. - * - * @param player the player to process - */ - public void processPlayer(Player player) { - player.setAllowFlight(false); - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/AuthGroupHandler.java b/src/main/java/fr/xephi/authme/data/limbo/AuthGroupHandler.java deleted file mode 100644 index 6e8c241a..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/AuthGroupHandler.java +++ /dev/null @@ -1,114 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.bukkit.entity.Player; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.util.Collection; -import java.util.Collections; - -/** - * Changes the permission group according to the auth status of the player and the configuration. - *

- * If this feature is enabled, the primary permissions group of a player is replaced until he has - * logged in. Some permission plugins have a notion of a primary group; for other permission plugins the - * first group is simply taken. - *

- * The groups that are used as replacement until the player logs in is configurable and depends on if - * the player is registered or not. Note that some (all?) permission systems require the group to actually - * exist for the replacement to take place. Furthermore, since some permission groups require that players - * be in at least one group, this will mean that the player is not removed from his primary group. - */ -class AuthGroupHandler implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AuthGroupHandler.class); - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private Settings settings; - - private UserGroup unregisteredGroup; - private UserGroup registeredGroup; - - AuthGroupHandler() { - } - - /** - * Sets the group of a player by its authentication status. - * - * @param player the player - * @param limbo the associated limbo player (nullable) - * @param groupType the group type - */ - void setGroup(Player player, LimboPlayer limbo, AuthGroupType groupType) { - if (!useAuthGroups()) { - return; - } - - Collection previousGroups = limbo == null ? Collections.emptyList() : limbo.getGroups(); - - switch (groupType) { - // Implementation note: some permission systems don't support players not being in any group, - // so add the new group before removing the old ones - case UNREGISTERED: - permissionsManager.addGroup(player, unregisteredGroup); - permissionsManager.removeGroup(player, registeredGroup); - permissionsManager.removeGroups(player, previousGroups); - break; - - case REGISTERED_UNAUTHENTICATED: - permissionsManager.addGroup(player, registeredGroup); - permissionsManager.removeGroup(player, unregisteredGroup); - permissionsManager.removeGroups(player, previousGroups); - - break; - - case LOGGED_IN: - permissionsManager.addGroups(player, previousGroups); - permissionsManager.removeGroup(player, unregisteredGroup); - permissionsManager.removeGroup(player, registeredGroup); - break; - - default: - throw new IllegalStateException("Encountered unhandled auth group type '" + groupType + "'"); - } - - logger.debug(() -> player.getName() + " changed to " - + groupType + ": has groups " + permissionsManager.getGroups(player)); - } - - /** - * Returns whether the auth permissions group function should be used. - * - * @return true if should be used, false otherwise - */ - private boolean useAuthGroups() { - // Check whether the permissions check is enabled - if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) { - return false; - } - - // Make sure group support is available - if (!permissionsManager.hasGroupSupport()) { - logger.warning("The current permissions system doesn't have group support, unable to set group!"); - return false; - } - return true; - } - - @Override - @PostConstruct - public void reload() { - unregisteredGroup = new UserGroup(settings.getProperty(PluginSettings.UNREGISTERED_GROUP)); - registeredGroup = new UserGroup(settings.getProperty(PluginSettings.REGISTERED_GROUP)); - } - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/AuthGroupType.java b/src/main/java/fr/xephi/authme/data/limbo/AuthGroupType.java deleted file mode 100644 index 501a20d8..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/AuthGroupType.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.data.limbo; - -/** - * Represents the group type based on the user's auth status. - */ -enum AuthGroupType { - - /** Player does not have an account. */ - UNREGISTERED, - - /** Player is registered but not logged in. */ - REGISTERED_UNAUTHENTICATED, - - /** Player is logged in. */ - LOGGED_IN - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboMessageType.java b/src/main/java/fr/xephi/authme/data/limbo/LimboMessageType.java deleted file mode 100644 index 4d0af3e5..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboMessageType.java +++ /dev/null @@ -1,11 +0,0 @@ -package fr.xephi.authme.data.limbo; - -public enum LimboMessageType { - - REGISTER, - - LOG_IN, - - TOTP_CODE - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayer.java b/src/main/java/fr/xephi/authme/data/limbo/LimboPlayer.java deleted file mode 100644 index 9446222f..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayer.java +++ /dev/null @@ -1,138 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask; -import fr.xephi.authme.task.MessageTask; -import org.bukkit.Location; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Represents a player which is not logged in and keeps track of certain states (like OP status, flying) - * which may be revoked from the player until he has logged in or registered. - */ -public class LimboPlayer { - - public static final float DEFAULT_WALK_SPEED = 0.2f; - public static final float DEFAULT_FLY_SPEED = 0.1f; - - private final boolean canFly; - private final boolean operator; - private final Collection groups; - private final Location loc; - private final float walkSpeed; - private final float flySpeed; - private MyScheduledTask timeoutTask = null; - private MessageTask messageTask = null; - - private LimboPlayerState state = LimboPlayerState.PASSWORD_REQUIRED; - - public LimboPlayer(Location loc, boolean operator, Collection groups, boolean fly, float walkSpeed, - float flySpeed) { - this.loc = loc; - this.operator = operator; - this.groups = new ArrayList<>(groups); // prevent bug #2413 - this.canFly = fly; - this.walkSpeed = walkSpeed; - this.flySpeed = flySpeed; - } - - /** - * Return the player's original location. - * - * @return The player's location - */ - public Location getLocation() { - return loc; - } - - /** - * Return whether the player is an operator or not (i.e. whether he is an OP). - * - * @return True if the player has OP status, false otherwise - */ - public boolean isOperator() { - return operator; - } - - /** - * Return the player's permissions groups. - * - * @return The permissions groups the player belongs to - */ - public Collection getGroups() { - return groups; - } - - public boolean isCanFly() { - return canFly; - } - - public float getWalkSpeed() { - return walkSpeed; - } - - public float getFlySpeed() { - return flySpeed; - } - - /** - * Return the timeout task, which kicks the player if he hasn't registered or logged in - * after a configurable amount of time. - * - * @return The timeout task associated to the player - */ - public MyScheduledTask getTimeoutTask() { - return timeoutTask; - } - - /** - * Set the timeout task of the player. The timeout task kicks the player after a configurable - * amount of time if he hasn't logged in or registered. - * - * @param timeoutTask The task to set - */ - public void setTimeoutTask(MyScheduledTask timeoutTask) { - if (this.timeoutTask != null) { - this.timeoutTask.cancel(); - } - this.timeoutTask = timeoutTask; - } - - /** - * Return the message task reminding the player to log in or register. - * - * @return The task responsible for sending the message regularly - */ - public MessageTask getMessageTask() { - return messageTask; - } - - /** - * Set the messages task responsible for telling the player to log in or register. - * - * @param messageTask The message task to set - */ - public void setMessageTask(MessageTask messageTask) { - if (this.messageTask != null) { - this.messageTask.cancel(); - } - this.messageTask = messageTask; - } - - /** - * Clears all tasks associated to the player. - */ - public void clearTasks() { - setMessageTask(null); - setTimeoutTask(null); - } - - public LimboPlayerState getState() { - return state; - } - - public void setState(LimboPlayerState state) { - this.state = state; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerState.java b/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerState.java deleted file mode 100644 index 5940ab20..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerState.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.xephi.authme.data.limbo; - -public enum LimboPlayerState { - - PASSWORD_REQUIRED, - - TOTP_REQUIRED - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerTaskManager.java b/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerTaskManager.java deleted file mode 100644 index ca5eaa1f..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboPlayerTaskManager.java +++ /dev/null @@ -1,117 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.captcha.RegistrationCaptchaManager; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.task.MessageTask; -import fr.xephi.authme.task.TimeoutTask; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND; - -/** - * Registers tasks associated with a LimboPlayer. - */ -class LimboPlayerTaskManager { - - @Inject - private Messages messages; - - @Inject - private Settings settings; - - @Inject - private BukkitService bukkitService; - - @Inject - private PlayerCache playerCache; - - @Inject - private RegistrationCaptchaManager registrationCaptchaManager; - - LimboPlayerTaskManager() { - } - - /** - * Registers a {@link MessageTask} for the given player name. - * - * @param player the player - * @param limbo the associated limbo player of the player - * @param messageType message type - */ - void registerMessageTask(Player player, LimboPlayer limbo, LimboMessageType messageType) { - int interval = settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL); - MessageResult result = getMessageKey(player.getName(), messageType); - if (interval > 0) { - String[] joinMessage = messages.retrieveSingle(player, result.messageKey, result.args).split("\n"); - MessageTask messageTask = new MessageTask(player, joinMessage); - bukkitService.runTaskTimer(messageTask, 2 * TICKS_PER_SECOND, (long) interval * TICKS_PER_SECOND); - limbo.setMessageTask(messageTask); - } - } - - /** - * Registers a {@link TimeoutTask} for the given player according to the configuration. - * - * @param player the player to register a timeout task for - * @param limbo the associated limbo player - */ - void registerTimeoutTask(Player player, LimboPlayer limbo) { - final int timeout = settings.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; - if (timeout > 0) { - String message = messages.retrieveSingle(player, MessageKey.LOGIN_TIMEOUT_ERROR); - MyScheduledTask task = bukkitService.runTaskLater(new TimeoutTask(player, message, playerCache), timeout); - limbo.setTimeoutTask(task); - } - } - - /** - * Null-safe method to set the muted flag on a message task. - * - * @param task the task to modify (or null) - * @param isMuted the value to set if task is not null - */ - static void setMuted(MessageTask task, boolean isMuted) { - if (task != null) { - task.setMuted(isMuted); - } - } - - /** - * Returns the appropriate message key according to the registration status and settings. - * - * @param name the player's name - * @param messageType the message to show - * @return the message key to display to the user - */ - private MessageResult getMessageKey(String name, LimboMessageType messageType) { - if (messageType == LimboMessageType.LOG_IN) { - return new MessageResult(MessageKey.LOGIN_MESSAGE); - } else if (messageType == LimboMessageType.TOTP_CODE) { - return new MessageResult(MessageKey.TWO_FACTOR_CODE_REQUIRED); - } else if (registrationCaptchaManager.isCaptchaRequired(name)) { - final String captchaCode = registrationCaptchaManager.getCaptchaCodeOrGenerateNew(name); - return new MessageResult(MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED, captchaCode); - } else { - return new MessageResult(MessageKey.REGISTER_MESSAGE); - } - } - - private static final class MessageResult { - private final MessageKey messageKey; - private final String[] args; - - MessageResult(MessageKey messageKey, String... args) { - this.messageKey = messageKey; - this.args = args; - } - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboService.java b/src/main/java/fr/xephi/authme/data/limbo/LimboService.java deleted file mode 100644 index c8b46922..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboService.java +++ /dev/null @@ -1,188 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.persistence.LimboPersistence; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SpawnLoader; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_ALLOW_FLIGHT; -import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_FLY_SPEED; -import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_WALK_SPEED; - -/** - * Service for managing players that are in "limbo," a temporary state players are - * put in which have joined but not yet logged in. - */ -public class LimboService { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(LimboService.class); - - private final Map entries = new ConcurrentHashMap<>(); - - @Inject - private Settings settings; - - @Inject - private LimboPlayerTaskManager taskManager; - - @Inject - private LimboServiceHelper helper; - - @Inject - private LimboPersistence persistence; - - @Inject - private AuthGroupHandler authGroupHandler; - - @Inject - private SpawnLoader spawnLoader; - - LimboService() { - } - - /** - * Creates a LimboPlayer for the given player and revokes all "limbo data" from the player. - * - * @param player the player to process - * @param isRegistered whether or not the player is registered - */ - public void createLimboPlayer(Player player, boolean isRegistered) { - final String name = player.getName().toLowerCase(Locale.ROOT); - - LimboPlayer limboFromDisk = persistence.getLimboPlayer(player); - if (limboFromDisk != null) { - logger.debug("LimboPlayer for `{0}` already exists on disk", name); - } - - LimboPlayer existingLimbo = entries.remove(name); - if (existingLimbo != null) { - existingLimbo.clearTasks(); - logger.debug("LimboPlayer for `{0}` already present in memory", name); - } - - Location location = spawnLoader.getPlayerLocationOrSpawn(player); - LimboPlayer limboPlayer = helper.merge(existingLimbo, limboFromDisk); - limboPlayer = helper.merge(helper.createLimboPlayer(player, isRegistered, location), limboPlayer); - - taskManager.registerMessageTask(player, limboPlayer, - isRegistered ? LimboMessageType.LOG_IN : LimboMessageType.REGISTER); - taskManager.registerTimeoutTask(player, limboPlayer); - helper.revokeLimboStates(player); - authGroupHandler.setGroup(player, limboPlayer, - isRegistered ? AuthGroupType.REGISTERED_UNAUTHENTICATED : AuthGroupType.UNREGISTERED); - entries.put(name, limboPlayer); - persistence.saveLimboPlayer(player, limboPlayer); - } - - /** - * Returns the limbo player for the given name, or null otherwise. - * - * @param name the name to retrieve the data for - * @return the associated limbo player, or null if none available - */ - public LimboPlayer getLimboPlayer(String name) { - return entries.get(name.toLowerCase(Locale.ROOT)); - } - - /** - * Returns whether there is a limbo player for the given name. - * - * @param name the name to check - * @return true if present, false otherwise - */ - public boolean hasLimboPlayer(String name) { - return entries.containsKey(name.toLowerCase(Locale.ROOT)); - } - - /** - * Restores the limbo data and subsequently deletes the entry. - *

- * Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and - * changing the permission group is handled by {@link fr.xephi.authme.data.limbo.AuthGroupHandler}. - * - * @param player the player whose data should be restored - */ - public void restoreData(Player player) { - String lowerName = player.getName().toLowerCase(Locale.ROOT); - LimboPlayer limbo = entries.remove(lowerName); - - if (limbo == null) { - logger.debug("No LimboPlayer found for `{0}` - cannot restore", lowerName); - } else { - player.setOp(limbo.isOperator()); - settings.getProperty(RESTORE_ALLOW_FLIGHT).restoreAllowFlight(player, limbo); - settings.getProperty(RESTORE_FLY_SPEED).restoreFlySpeed(player, limbo); - settings.getProperty(RESTORE_WALK_SPEED).restoreWalkSpeed(player, limbo); - limbo.clearTasks(); - logger.debug("Restored LimboPlayer stats for `{0}`", lowerName); - persistence.removeLimboPlayer(player); - } - authGroupHandler.setGroup(player, limbo, AuthGroupType.LOGGED_IN); - } - - /** - * Creates new tasks for the given player and cancels the old ones for a newly registered player. - * This resets his time to log in (TimeoutTask) and updates the message he is shown (MessageTask). - * - * @param player the player to reset the tasks for - */ - public void replaceTasksAfterRegistration(Player player) { - Optional limboPlayer = getLimboOrLogError(player, "reset tasks"); - limboPlayer.ifPresent(limbo -> { - taskManager.registerTimeoutTask(player, limbo); - taskManager.registerMessageTask(player, limbo, LimboMessageType.LOG_IN); - }); - authGroupHandler.setGroup(player, limboPlayer.orElse(null), AuthGroupType.REGISTERED_UNAUTHENTICATED); - } - - /** - * Resets the message task associated with the player's LimboPlayer. - * - * @param player the player to set a new message task for - * @param messageType the message to show for the limbo player - */ - public void resetMessageTask(Player player, LimboMessageType messageType) { - getLimboOrLogError(player, "reset message task") - .ifPresent(limbo -> taskManager.registerMessageTask(player, limbo, messageType)); - } - - /** - * @param player the player whose message task should be muted - */ - public void muteMessageTask(Player player) { - getLimboOrLogError(player, "mute message task") - .ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), true)); - } - - /** - * @param player the player whose message task should be unmuted - */ - public void unmuteMessageTask(Player player) { - getLimboOrLogError(player, "unmute message task") - .ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), false)); - } - - /** - * Returns the limbo player for the given player or logs an error. - * - * @param player the player to retrieve the limbo player for - * @param context the action for which the limbo player is being retrieved (for logging) - * @return Optional with the limbo player - */ - private Optional getLimboOrLogError(Player player, String context) { - LimboPlayer limbo = entries.get(player.getName().toLowerCase(Locale.ROOT)); - if (limbo == null) { - logger.debug("No LimboPlayer found for `{0}`. Action: {1}", player.getName(), context); - } - return Optional.ofNullable(limbo); - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboServiceHelper.java b/src/main/java/fr/xephi/authme/data/limbo/LimboServiceHelper.java deleted file mode 100644 index a3edb164..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/LimboServiceHelper.java +++ /dev/null @@ -1,115 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.LimboSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import static fr.xephi.authme.util.Utils.isCollectionEmpty; -import static java.util.stream.Collectors.toList; - -/** - * Helper class for the LimboService. - */ -class LimboServiceHelper { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(LimboServiceHelper.class); - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private Settings settings; - - /** - * Creates a LimboPlayer with the given player's details. - * - * @param player the player to process - * @param isRegistered whether the player is registered - * @param location the player location - * @return limbo player with the player's data - */ - LimboPlayer createLimboPlayer(Player player, boolean isRegistered, Location location) { - // For safety reasons an unregistered player should not have OP status after registration - boolean isOperator = isRegistered && player.isOp(); - boolean flyEnabled = player.getAllowFlight(); - float walkSpeed = player.getWalkSpeed(); - float flySpeed = player.getFlySpeed(); - Collection playerGroups = permissionsManager.hasGroupSupport() - ? permissionsManager.getGroups(player) : Collections.emptyList(); - - List groupNames = playerGroups.stream() - .map(UserGroup::getGroupName) - .collect(toList()); - - logger.debug("Player `{0}` has groups `{1}`", player.getName(), String.join(", ", groupNames)); - return new LimboPlayer(location, isOperator, playerGroups, flyEnabled, walkSpeed, flySpeed); - } - - /** - * Removes the data that is saved in a LimboPlayer from the player. - *

- * Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and - * changing the permission group is handled by {@link fr.xephi.authme.data.limbo.AuthGroupHandler}. - * - * @param player the player to set defaults to - */ - void revokeLimboStates(Player player) { - player.setOp(false); - settings.getProperty(LimboSettings.RESTORE_ALLOW_FLIGHT) - .processPlayer(player); - - if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) { - player.setFlySpeed(0.0f); - player.setWalkSpeed(0.0f); - } - } - - /** - * Merges two existing LimboPlayer instances of a player. Merging is done the following way: - *

    - *
  • isOperator, allowFlight: true if either limbo has true
  • - *
  • flySpeed, walkSpeed: maximum value of either limbo player
  • - *
  • groups, location: from old limbo if not empty/null, otherwise from new limbo
  • - *
- * - * @param newLimbo the new limbo player - * @param oldLimbo the old limbo player - * @return merged limbo player if both arguments are not null, otherwise the first non-null argument - */ - LimboPlayer merge(LimboPlayer newLimbo, LimboPlayer oldLimbo) { - if (newLimbo == null) { - return oldLimbo; - } else if (oldLimbo == null) { - return newLimbo; - } - - boolean isOperator = newLimbo.isOperator() || oldLimbo.isOperator(); - boolean canFly = newLimbo.isCanFly() || oldLimbo.isCanFly(); - float flySpeed = Math.max(newLimbo.getFlySpeed(), oldLimbo.getFlySpeed()); - float walkSpeed = Math.max(newLimbo.getWalkSpeed(), oldLimbo.getWalkSpeed()); - Collection groups = getLimboGroups(oldLimbo.getGroups(), newLimbo.getGroups()); - Location location = firstNotNull(oldLimbo.getLocation(), newLimbo.getLocation()); - - return new LimboPlayer(location, isOperator, groups, canFly, walkSpeed, flySpeed); - } - - private static Location firstNotNull(Location first, Location second) { - return first == null ? second : first; - } - - private Collection getLimboGroups(Collection oldLimboGroups, - Collection newLimboGroups) { - logger.debug("Limbo merge: new and old groups are `{0}` and `{1}`", newLimboGroups, oldLimboGroups); - return isCollectionEmpty(oldLimboGroups) ? newLimboGroups : oldLimboGroups; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/UserGroup.java b/src/main/java/fr/xephi/authme/data/limbo/UserGroup.java deleted file mode 100644 index 9ed028a5..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/UserGroup.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import java.util.Map; -import java.util.Objects; - -public class UserGroup { - - private String groupName; - private Map contextMap; - - public UserGroup(String groupName) { - this.groupName = groupName; - } - - public UserGroup(String groupName, Map contextMap) { - this.groupName = groupName; - this.contextMap = contextMap; - } - - public String getGroupName() { - return groupName; - } - - public Map getContextMap() { - return contextMap; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UserGroup userGroup = (UserGroup) o; - return Objects.equals(groupName, userGroup.groupName) - && Objects.equals(contextMap, userGroup.contextMap); - } - - @Override - public int hashCode() { - return Objects.hash(groupName, contextMap); - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/WalkFlySpeedRestoreType.java b/src/main/java/fr/xephi/authme/data/limbo/WalkFlySpeedRestoreType.java deleted file mode 100644 index f4a24901..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/WalkFlySpeedRestoreType.java +++ /dev/null @@ -1,123 +0,0 @@ -package fr.xephi.authme.data.limbo; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.entity.Player; - -/** - * Possible types to restore the walk and fly speed from LimboPlayer - * back to Bukkit Player. - */ -public enum WalkFlySpeedRestoreType { - - /** - * Restores from LimboPlayer to Player. - */ - RESTORE { - @Override - public void restoreFlySpeed(Player player, LimboPlayer limbo) { - logger.debug(() -> "Restoring fly speed for LimboPlayer " + player.getName() + " to " - + limbo.getFlySpeed() + " (RESTORE mode)"); - player.setFlySpeed(limbo.getFlySpeed()); - } - - @Override - public void restoreWalkSpeed(Player player, LimboPlayer limbo) { - logger.debug(() -> "Restoring walk speed for LimboPlayer " + player.getName() + " to " - + limbo.getWalkSpeed() + " (RESTORE mode)"); - player.setWalkSpeed(limbo.getWalkSpeed()); - } - }, - - /** - * Restores from LimboPlayer, using the default speed if the speed on LimboPlayer is 0. - */ - RESTORE_NO_ZERO { - @Override - public void restoreFlySpeed(Player player, LimboPlayer limbo) { - float limboFlySpeed = limbo.getFlySpeed(); - if (limboFlySpeed > 0.01f) { - logger.debug(() -> "Restoring fly speed for LimboPlayer " + player.getName() + " to " - + limboFlySpeed + " (RESTORE_NO_ZERO mode)"); - player.setFlySpeed(limboFlySpeed); - } else { - logger.debug(() -> "Restoring fly speed for LimboPlayer " + player.getName() - + " to DEFAULT, it was 0! (RESTORE_NO_ZERO mode)"); - player.setFlySpeed(LimboPlayer.DEFAULT_FLY_SPEED); - } - } - - @Override - public void restoreWalkSpeed(Player player, LimboPlayer limbo) { - float limboWalkSpeed = limbo.getWalkSpeed(); - if (limboWalkSpeed > 0.01f) { - logger.debug(() -> "Restoring walk speed for LimboPlayer " + player.getName() + " to " - + limboWalkSpeed + " (RESTORE_NO_ZERO mode)"); - player.setWalkSpeed(limboWalkSpeed); - } else { - logger.debug(() -> "Restoring walk speed for LimboPlayer " + player.getName() + "" - + " to DEFAULT, it was 0! (RESTORE_NO_ZERO mode)"); - player.setWalkSpeed(LimboPlayer.DEFAULT_WALK_SPEED); - } - } - }, - - /** - * Uses the max speed of Player (current speed) and the LimboPlayer. - */ - MAX_RESTORE { - @Override - public void restoreFlySpeed(Player player, LimboPlayer limbo) { - float newSpeed = Math.max(player.getFlySpeed(), limbo.getFlySpeed()); - logger.debug(() -> "Restoring fly speed for LimboPlayer " + player.getName() + " to " + newSpeed - + " (Current: " + player.getFlySpeed() + ", Limbo: " + limbo.getFlySpeed() + ") (MAX_RESTORE mode)"); - player.setFlySpeed(newSpeed); - } - - @Override - public void restoreWalkSpeed(Player player, LimboPlayer limbo) { - float newSpeed = Math.max(player.getWalkSpeed(), limbo.getWalkSpeed()); - logger.debug(() -> "Restoring walk speed for LimboPlayer " + player.getName() + " to " + newSpeed - + " (Current: " + player.getWalkSpeed() + ", Limbo: " + limbo.getWalkSpeed() + ") (MAX_RESTORE mode)"); - player.setWalkSpeed(newSpeed); - } - }, - - /** - * Always sets the default speed to the player. - */ - DEFAULT { - @Override - public void restoreFlySpeed(Player player, LimboPlayer limbo) { - logger.debug(() -> "Restoring fly speed for LimboPlayer " + player.getName() - + " to DEFAULT (DEFAULT mode)"); - player.setFlySpeed(LimboPlayer.DEFAULT_FLY_SPEED); - } - - @Override - public void restoreWalkSpeed(Player player, LimboPlayer limbo) { - logger.debug(() -> "Restoring walk speed for LimboPlayer " + player.getName() - + " to DEFAULT (DEFAULT mode)"); - player.setWalkSpeed(LimboPlayer.DEFAULT_WALK_SPEED); - } - }; - - private static final ConsoleLogger logger = ConsoleLoggerFactory.get(WalkFlySpeedRestoreType.class); - - /** - * Restores the fly speed from Limbo to Player according to the restoration type. - * - * @param player the player to modify - * @param limbo the limbo player to read from - */ - public abstract void restoreFlySpeed(Player player, LimboPlayer limbo); - - /** - * Restores the walk speed from Limbo to Player according to the restoration type. - * - * @param player the player to modify - * @param limbo the limbo player to read from - */ - public abstract void restoreWalkSpeed(Player player, LimboPlayer limbo); - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java deleted file mode 100644 index 9708ce88..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java +++ /dev/null @@ -1,228 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import com.google.common.io.Files; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.LimboSettings; -import fr.xephi.authme.util.FileUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.io.File; -import java.io.FileWriter; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * Persistence handler for LimboPlayer objects by distributing the objects to store - * in various segments (buckets) based on the start of the player's UUID. - */ -class DistributedFilesPersistenceHandler implements LimboPersistenceHandler { - - private static final Type LIMBO_MAP_TYPE = new TypeToken>(){}.getType(); - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(DistributedFilesPersistenceHandler.class); - private final File cacheFolder; - private final Gson gson; - private final SegmentNameBuilder segmentNameBuilder; - - @Inject - DistributedFilesPersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService, Settings settings) { - cacheFolder = new File(dataFolder, "playerdata"); - FileUtils.createDirectory(cacheFolder); - - gson = new GsonBuilder() - .registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer()) - .registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService)) - .setPrettyPrinting() - .create(); - - segmentNameBuilder = new SegmentNameBuilder(settings.getProperty(LimboSettings.DISTRIBUTION_SIZE)); - - convertOldDataToCurrentSegmentScheme(); - deleteEmptyFiles(); - } - - @Override - public LimboPlayer getLimboPlayer(Player player) { - String uuid = player.getUniqueId().toString(); - File file = getPlayerSegmentFile(uuid); - Map entries = readLimboPlayers(file); - return entries == null ? null : entries.get(uuid); - } - - @Override - public void saveLimboPlayer(Player player, LimboPlayer limbo) { - String uuid = player.getUniqueId().toString(); - File file = getPlayerSegmentFile(uuid); - - Map entries = null; - if (file.exists()) { - entries = readLimboPlayers(file); - } else { - FileUtils.create(file); - } - /* intentionally separate if */ - if (entries == null) { - entries = new HashMap<>(); - } - - entries.put(uuid, limbo); - saveEntries(entries, file); - } - - @Override - public void removeLimboPlayer(Player player) { - String uuid = player.getUniqueId().toString(); - File file = getPlayerSegmentFile(uuid); - if (file.exists()) { - Map entries = readLimboPlayers(file); - if (entries != null && entries.remove(uuid) != null) { - saveEntries(entries, file); - } - } - } - - @Override - public LimboPersistenceType getType() { - return LimboPersistenceType.DISTRIBUTED_FILES; - } - - private void saveEntries(Map entries, File file) { - try (FileWriter fw = new FileWriter(file)) { - gson.toJson(entries, fw); - } catch (Exception e) { - logger.logException("Could not write to '" + file + "':", e); - } - } - - private Map readLimboPlayers(File file) { - if (!file.exists()) { - return null; - } - - try { - return gson.fromJson(Files.asCharSource(file, StandardCharsets.UTF_8).read(), LIMBO_MAP_TYPE); - } catch (Exception e) { - logger.logException("Failed reading '" + file + "':", e); - } - return null; - } - - private File getPlayerSegmentFile(String uuid) { - String segment = segmentNameBuilder.createSegmentName(uuid); - return getSegmentFile(segment); - } - - private File getSegmentFile(String segmentId) { - return new File(cacheFolder, segmentId + "-limbo.json"); - } - - /** - * Loads segment files in the cache folder that don't correspond to the current segmenting scheme - * and migrates the data into files of the current segments. This allows a player to change the - * segment size without any loss of data. - */ - private void convertOldDataToCurrentSegmentScheme() { - String currentPrefix = segmentNameBuilder.getPrefix(); - File[] files = listFiles(cacheFolder); - Map allLimboPlayers = new HashMap<>(); - List migratedFiles = new ArrayList<>(); - - for (File file : files) { - if (isLimboJsonFile(file) && !file.getName().startsWith(currentPrefix)) { - Map data = readLimboPlayers(file); - if (data != null) { - allLimboPlayers.putAll(data); - migratedFiles.add(file); - } - } - } - - if (!allLimboPlayers.isEmpty()) { - saveToNewSegments(allLimboPlayers); - migratedFiles.forEach(FileUtils::delete); - } - } - - /** - * Saves the LimboPlayer data read from old segmenting schemes into the current segmenting scheme. - * - * @param limbosFromOldSegments the limbo players to store into the current segment files - */ - private void saveToNewSegments(Map limbosFromOldSegments) { - Map> limboBySegment = groupBySegment(limbosFromOldSegments); - - logger.info("Saving " + limbosFromOldSegments.size() + " LimboPlayers from old segments into " - + limboBySegment.size() + " current segments"); - for (Map.Entry> entry : limboBySegment.entrySet()) { - File file = getSegmentFile(entry.getKey()); - Map limbosToSave = Optional.ofNullable(readLimboPlayers(file)) - .orElseGet(HashMap::new); - limbosToSave.putAll(entry.getValue()); - saveEntries(limbosToSave, file); - } - } - - /** - * Converts a Map of UUID to LimboPlayers to a 2-dimensional Map of LimboPlayers by segment ID and UUID. - * {@code Map(uuid -> LimboPlayer) to Map(segment -> Map(uuid -> LimboPlayer))} - * - * @param readLimboPlayers the limbo players to order by segment - * @return limbo players ordered by segment ID and associated player UUID - */ - private Map> groupBySegment(Map readLimboPlayers) { - Map> limboBySegment = new HashMap<>(); - for (Map.Entry entry : readLimboPlayers.entrySet()) { - String segmentId = segmentNameBuilder.createSegmentName(entry.getKey()); - limboBySegment.computeIfAbsent(segmentId, s -> new HashMap<>()) - .put(entry.getKey(), entry.getValue()); - } - return limboBySegment; - } - - /** - * Deletes segment files that are empty. - */ - private void deleteEmptyFiles() { - File[] files = listFiles(cacheFolder); - - long deletedFiles = Arrays.stream(files) - // typically the size is 2 because there's an empty JSON map: {} - .filter(f -> isLimboJsonFile(f) && f.length() < 3) - .peek(FileUtils::delete) - .count(); - logger.debug("Limbo: Deleted {0} empty segment files", deletedFiles); - } - - /** - * @param file the file to check - * @return true if it is a segment file storing Limbo data, false otherwise - */ - private static boolean isLimboJsonFile(File file) { - String name = file.getName(); - return name.startsWith("seg") && name.endsWith("-limbo.json"); - } - - private File[] listFiles(File folder) { - File[] files = folder.listFiles(); - if (files == null) { - logger.warning("Could not get files of '" + folder + "'"); - return new File[0]; - } - return files; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java deleted file mode 100644 index 9772ec06..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/IndividualFilesPersistenceHandler.java +++ /dev/null @@ -1,92 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import com.google.common.io.Files; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.util.FileUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -/** - * Saves LimboPlayer objects as JSON into individual files. - */ -class IndividualFilesPersistenceHandler implements LimboPersistenceHandler { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(IndividualFilesPersistenceHandler.class); - - private final Gson gson; - private final File cacheDir; - - @Inject - IndividualFilesPersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService) { - cacheDir = new File(dataFolder, "playerdata"); - if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { - logger.warning("Failed to create playerdata directory '" + cacheDir + "'"); - } - gson = new GsonBuilder() - .registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer()) - .registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService)) - .setPrettyPrinting() - .create(); - } - - @Override - public LimboPlayer getLimboPlayer(Player player) { - String id = player.getUniqueId().toString(); - File file = new File(cacheDir, id + File.separator + "data.json"); - if (!file.exists()) { - return null; - } - - try { - String str = Files.asCharSource(file, StandardCharsets.UTF_8).read(); - return gson.fromJson(str, LimboPlayer.class); - } catch (IOException e) { - logger.logException("Could not read player data on disk for '" + player.getName() + "'", e); - return null; - } - } - - @Override - public void saveLimboPlayer(Player player, LimboPlayer limboPlayer) { - String id = player.getUniqueId().toString(); - try { - File file = new File(cacheDir, id + File.separator + "data.json"); - Files.createParentDirs(file); - Files.touch(file); - Files.write(gson.toJson(limboPlayer), file, StandardCharsets.UTF_8); - } catch (IOException e) { - logger.logException("Failed to write " + player.getName() + " data:", e); - } - } - - /** - * Removes the LimboPlayer. This will delete the - * "playerdata/<uuid or name>/" folder from disk. - * - * @param player player to remove - */ - @Override - public void removeLimboPlayer(Player player) { - String id = player.getUniqueId().toString(); - File file = new File(cacheDir, id); - if (file.exists()) { - FileUtils.purgeDirectory(file); - FileUtils.delete(file); - } - } - - @Override - public LimboPersistenceType getType() { - return LimboPersistenceType.INDIVIDUAL_FILES; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java deleted file mode 100644 index 844c9cdf..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java +++ /dev/null @@ -1,82 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import ch.jalu.injector.factory.Factory; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.LimboSettings; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Handles the persistence of LimboPlayers. - */ -public class LimboPersistence implements SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(LimboPersistence.class); - - private final Factory handlerFactory; - - private LimboPersistenceHandler handler; - - @Inject - LimboPersistence(Settings settings, Factory handlerFactory) { - this.handlerFactory = handlerFactory; - reload(settings); - } - - /** - * Retrieves the LimboPlayer for the given player if available. - * - * @param player the player to retrieve the LimboPlayer for - * @return the player's limbo player, or null if not available - */ - public LimboPlayer getLimboPlayer(Player player) { - try { - return handler.getLimboPlayer(player); - } catch (Exception e) { - logger.logException("Could not get LimboPlayer for '" + player.getName() + "'", e); - } - return null; - } - - /** - * Saves the given LimboPlayer for the provided player. - * - * @param player the player to save the LimboPlayer for - * @param limbo the limbo player to save - */ - public void saveLimboPlayer(Player player, LimboPlayer limbo) { - try { - handler.saveLimboPlayer(player, limbo); - } catch (Exception e) { - logger.logException("Could not save LimboPlayer for '" + player.getName() + "'", e); - } - } - - /** - * Removes the LimboPlayer for the given player. - * - * @param player the player whose LimboPlayer should be removed - */ - public void removeLimboPlayer(Player player) { - try { - handler.removeLimboPlayer(player); - } catch (Exception e) { - logger.logException("Could not remove LimboPlayer for '" + player.getName() + "'", e); - } - } - - @Override - public void reload(Settings settings) { - LimboPersistenceType persistenceType = settings.getProperty(LimboSettings.LIMBO_PERSISTENCE_TYPE); - // If we're changing from an existing handler, output a quick hint that nothing is converted. - if (handler != null && handler.getType() != persistenceType) { - logger.info("Limbo persistence type has changed! Note that the data is not converted."); - } - handler = handlerFactory.newInstance(persistenceType.getImplementationClass()); - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceHandler.java deleted file mode 100644 index 95e88aad..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import fr.xephi.authme.data.limbo.LimboPlayer; -import org.bukkit.entity.Player; - -/** - * Handles I/O for storing LimboPlayer objects. - */ -interface LimboPersistenceHandler { - - /** - * Returns the limbo player for the given player if it exists. - * - * @param player the player - * @return the stored limbo player, or null if not available - */ - LimboPlayer getLimboPlayer(Player player); - - /** - * Saves the given limbo player for the given player to the disk. - * - * @param player the player to save the limbo player for - * @param limbo the limbo player to save - */ - void saveLimboPlayer(Player player, LimboPlayer limbo); - - /** - * Removes the limbo player from the disk. - * - * @param player the player whose limbo player should be removed - */ - void removeLimboPlayer(Player player); - - /** - * @return the type of the limbo persistence implementation - */ - LimboPersistenceType getType(); - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java deleted file mode 100644 index 8119e669..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -/** - * Types of persistence for LimboPlayer objects. - */ -public enum LimboPersistenceType { - - /** Store each LimboPlayer in a separate file. */ - INDIVIDUAL_FILES(IndividualFilesPersistenceHandler.class), - - /** Store LimboPlayers distributed in a configured number of files. */ - DISTRIBUTED_FILES(DistributedFilesPersistenceHandler.class), - - /** No persistence to disk. */ - DISABLED(NoOpPersistenceHandler.class); - - private final Class implementationClass; - - /** - * Constructor. - * - * @param implementationClass the implementation class - */ - LimboPersistenceType(Class implementationClass) { - this.implementationClass= implementationClass; - } - - /** - * @return class implementing the persistence type - */ - public Class getImplementationClass() { - return implementationClass; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerDeserializer.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerDeserializer.java deleted file mode 100644 index 6dea20ef..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerDeserializer.java +++ /dev/null @@ -1,163 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.Location; -import org.bukkit.World; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.CAN_FLY; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.FLY_SPEED; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.GROUPS; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.IS_OP; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOCATION; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_PITCH; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_WORLD; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_X; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Y; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_YAW; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Z; -import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.WALK_SPEED; -import static java.util.Optional.ofNullable; - -/** - * Converts a JsonElement to a LimboPlayer. - */ -class LimboPlayerDeserializer implements JsonDeserializer { - - private static final String GROUP_LEGACY = "group"; - private static final String CONTEXT_MAP = "contextMap"; - private static final String GROUP_NAME = "groupName"; - - private BukkitService bukkitService; - - LimboPlayerDeserializer(BukkitService bukkitService) { - this.bukkitService = bukkitService; - } - - @Override - public LimboPlayer deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - if (jsonObject == null) { - return null; - } - - Location loc = deserializeLocation(jsonObject); - boolean operator = getBoolean(jsonObject, IS_OP); - - Collection groups = getLimboGroups(jsonObject); - boolean canFly = getBoolean(jsonObject, CAN_FLY); - float walkSpeed = getFloat(jsonObject, WALK_SPEED, LimboPlayer.DEFAULT_WALK_SPEED); - float flySpeed = getFloat(jsonObject, FLY_SPEED, LimboPlayer.DEFAULT_FLY_SPEED); - - return new LimboPlayer(loc, operator, groups, canFly, walkSpeed, flySpeed); - } - - private Location deserializeLocation(JsonObject jsonObject) { - JsonElement e; - if ((e = jsonObject.getAsJsonObject(LOCATION)) != null) { - JsonObject locationObject = e.getAsJsonObject(); - World world = bukkitService.getWorld(getString(locationObject, LOC_WORLD)); - if (world != null) { - double x = getDouble(locationObject, LOC_X); - double y = getDouble(locationObject, LOC_Y); - double z = getDouble(locationObject, LOC_Z); - float yaw = getFloat(locationObject, LOC_YAW); - float pitch = getFloat(locationObject, LOC_PITCH); - return new Location(world, x, y, z, yaw, pitch); - } - } - return null; - } - - private static String getString(JsonObject jsonObject, String memberName) { - JsonElement element = jsonObject.get(memberName); - return element != null ? element.getAsString() : ""; - } - - /** - * @param jsonObject LimboPlayer represented as JSON - * @return The list of UserGroups create from JSON - */ - private static List getLimboGroups(JsonObject jsonObject) { - JsonElement element = jsonObject.get(GROUPS); - if (element == null) { - String legacyGroup = ofNullable(jsonObject.get(GROUP_LEGACY)).map(JsonElement::getAsString).orElse(null); - return legacyGroup == null ? Collections.emptyList() : - Collections.singletonList(new UserGroup(legacyGroup, null)); - } - List result = new ArrayList<>(); - JsonArray jsonArray = element.getAsJsonArray(); - for (JsonElement arrayElement : jsonArray) { - if (!arrayElement.isJsonObject()) { - result.add(new UserGroup(arrayElement.getAsString(), null)); - } else { - JsonObject jsonGroup = arrayElement.getAsJsonObject(); - Map contextMap = null; - if (jsonGroup.has(CONTEXT_MAP)) { - JsonElement contextMapJson = jsonGroup.get("contextMap"); - Type type = new TypeToken>() { - }.getType(); - contextMap = new Gson().fromJson(contextMapJson.getAsString(), type); - } - - String groupName = jsonGroup.get(GROUP_NAME).getAsString(); - result.add(new UserGroup(groupName, contextMap)); - } - } - return result; - } - - private static boolean getBoolean(JsonObject jsonObject, String memberName) { - JsonElement element = jsonObject.get(memberName); - return element != null && element.getAsBoolean(); - } - - private static float getFloat(JsonObject jsonObject, String memberName) { - return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, 0.0f); - } - - private static float getFloat(JsonObject jsonObject, String memberName, float defaultValue) { - return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, defaultValue); - } - - private static double getDouble(JsonObject jsonObject, String memberName) { - return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsDouble, 0.0); - } - - /** - * Gets a number from the given JsonElement safely. - * - * @param jsonElement the element to retrieve the number from - * @param numberFunction the function to get the number from the element - * @param defaultValue the value to return if the element is null or the number cannot be retrieved - * @param the number type - * @return the number from the given JSON element, or the default value - */ - private static N getNumberFromElement(JsonElement jsonElement, - Function numberFunction, - N defaultValue) { - if (jsonElement != null) { - try { - return numberFunction.apply(jsonElement); - } catch (NumberFormatException ignore) { - } - } - return defaultValue; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerSerializer.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerSerializer.java deleted file mode 100644 index eaad86b7..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPlayerSerializer.java +++ /dev/null @@ -1,71 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import fr.xephi.authme.data.limbo.LimboPlayer; -import org.bukkit.Location; - -import java.lang.reflect.Type; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Converts a LimboPlayer to a JsonElement. - */ -class LimboPlayerSerializer implements JsonSerializer { - - static final String LOCATION = "location"; - static final String LOC_WORLD = "world"; - static final String LOC_X = "x"; - static final String LOC_Y = "y"; - static final String LOC_Z = "z"; - static final String LOC_YAW = "yaw"; - static final String LOC_PITCH = "pitch"; - - static final String GROUPS = "groups"; - static final String IS_OP = "operator"; - static final String CAN_FLY = "can-fly"; - static final String WALK_SPEED = "walk-speed"; - static final String FLY_SPEED = "fly-speed"; - - private static final Gson GSON = new Gson(); - - - @Override - public JsonElement serialize(LimboPlayer limboPlayer, Type type, JsonSerializationContext context) { - Location loc = limboPlayer.getLocation(); - JsonObject locationObject = new JsonObject(); - locationObject.addProperty(LOC_WORLD, loc.getWorld().getName()); - locationObject.addProperty(LOC_X, loc.getX()); - locationObject.addProperty(LOC_Y, loc.getY()); - locationObject.addProperty(LOC_Z, loc.getZ()); - locationObject.addProperty(LOC_YAW, loc.getYaw()); - locationObject.addProperty(LOC_PITCH, loc.getPitch()); - - JsonObject obj = new JsonObject(); - obj.add(LOCATION, locationObject); - - List groups = limboPlayer.getGroups().stream().map(g -> { - JsonObject jsonGroup = new JsonObject(); - jsonGroup.addProperty("groupName", g.getGroupName()); - if (g.getContextMap() != null) { - jsonGroup.addProperty("contextMap", GSON.toJson(g.getContextMap())); - } - return jsonGroup; - }).collect(Collectors.toList()); - - JsonArray jsonGroups = new JsonArray(); - groups.forEach(jsonGroups::add); - obj.add(GROUPS, jsonGroups); - - obj.addProperty(IS_OP, limboPlayer.isOperator()); - obj.addProperty(CAN_FLY, limboPlayer.isCanFly()); - obj.addProperty(WALK_SPEED, limboPlayer.getWalkSpeed()); - obj.addProperty(FLY_SPEED, limboPlayer.getFlySpeed()); - return obj; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/NoOpPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/NoOpPersistenceHandler.java deleted file mode 100644 index ac6ff9b3..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/NoOpPersistenceHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import fr.xephi.authme.data.limbo.LimboPlayer; -import org.bukkit.entity.Player; - -/** - * Limbo player persistence implementation that does nothing. - */ -class NoOpPersistenceHandler implements LimboPersistenceHandler { - - @Override - public LimboPlayer getLimboPlayer(Player player) { - return null; - } - - @Override - public void saveLimboPlayer(Player player, LimboPlayer limbo) { - // noop - } - - @Override - public void removeLimboPlayer(Player player) { - // noop - } - - @Override - public LimboPersistenceType getType() { - return LimboPersistenceType.DISABLED; - } -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentNameBuilder.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentNameBuilder.java deleted file mode 100644 index 24e0737d..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentNameBuilder.java +++ /dev/null @@ -1,73 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -import java.util.HashMap; -import java.util.Map; - -/** - * Creates segment names for {@link DistributedFilesPersistenceHandler}. - */ -class SegmentNameBuilder { - - private final int length; - private final int distribution; - private final String prefix; - private final Map charToSegmentChar; - - /** - * Constructor. - * - * @param partition the segment configuration - */ - SegmentNameBuilder(SegmentSize partition) { - this.length = partition.getLength(); - this.distribution = partition.getDistribution(); - this.prefix = "seg" + partition.getTotalSegments() + "-"; - this.charToSegmentChar = buildCharMap(distribution); - } - - /** - * Returns the segment ID for the given UUID. - * - * @param uuid the player's uuid to get the segment for - * @return id the uuid belongs to - */ - String createSegmentName(String uuid) { - if (distribution == 16) { - return prefix + uuid.substring(0, length); - } else { - return prefix + buildSegmentName(uuid.substring(0, length).toCharArray()); - } - } - - /** - * @return the prefix used for the current segment configuration - */ - String getPrefix() { - return prefix; - } - - private String buildSegmentName(char[] chars) { - if (chars.length == 1) { - return String.valueOf(charToSegmentChar.get(chars[0])); - } - - StringBuilder sb = new StringBuilder(chars.length); - for (char chr : chars) { - sb.append(charToSegmentChar.get(chr)); - } - return sb.toString(); - } - - private static Map buildCharMap(int distribution) { - final char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - final int divisor = 16 / distribution; - - Map charToSegmentChar = new HashMap<>(); - for (int i = 0; i < hexChars.length; ++i) { - int mappedChar = i / divisor; - charToSegmentChar.put(hexChars[i], hexChars[mappedChar]); - } - return charToSegmentChar; - } - -} diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentSize.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentSize.java deleted file mode 100644 index 0e290cea..00000000 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentSize.java +++ /dev/null @@ -1,94 +0,0 @@ -package fr.xephi.authme.data.limbo.persistence; - -/** - * Configuration for the total number of segments to use. - *

- * The {@link DistributedFilesPersistenceHandler} reduces the number of files by assigning each UUID - * to a segment. This enum allows to define how many segments the UUIDs should be distributed in. - *

- * Segments are defined by a distribution and a length. The distribution defines - * to how many outputs a single hexadecimal characters should be mapped. So e.g. a distribution - * of 3 means that all hexadecimal characters 0-f should be distributed over three different - * outputs evenly. The {@link SegmentNameBuilder} simply uses hexadecimal characters as outputs, - * so e.g. with a distribution of 3 all hex characters 0-f are mapped to 0, 1, or 2. - *

- * To ensure an even distribution the segments must be powers of 2. Trivially, to implement a - * distribution of 16, the same character may be returned as was input (since 0-f make up 16 - * characters). A distribution of 1, on the other hand, means that the same output is returned - * regardless of the input character. - *

- * The length parameter defines how many characters of a player's UUID should be used to - * create the segment ID. In other words, with a distribution of 2 and a length of 3, the first - * three characters of the UUID are taken into consideration, each mapped to one of two possible - * characters. For instance, a UUID starting with "0f5c9321" may yield the segment ID "010." - * Such a segment ID defines in which file the given UUID can be found and stored. - *

- * The number of segments such a configuration yields is computed as {@code distribution ^ length}, - * since distribution defines how many outputs there are per digit, and length defines the number - * of digits. For instance, a distribution of 2 and a length of 3 will yield segment IDs 000, 001, - * 010, 011, 100, 101, 110 and 111 (i.e. all binary numbers from 0 to 7). - *

- * There are multiple possibilities to achieve certain segment totals, e.g. 8 different segments - * may be created by setting distribution to 8 and length to 1, or distr. to 2 and length to 3. - * Where possible, prefer a length of 1 (no string concatenation required) or a distribution of - * 16 (no remapping of the characters required). - */ -public enum SegmentSize { - - /** 1. */ - ONE(1, 1), - - // /** 2. */ - // TWO(2, 1), - - /** 4. */ - FOUR(4, 1), - - /** 8. */ - EIGHT(8, 1), - - /** 16. */ - SIXTEEN(16, 1), - - /** 32. */ - THIRTY_TWO(2, 5), - - /** 64. */ - SIXTY_FOUR(4, 3), - - /** 128. */ - ONE_TWENTY(2, 7), - - /** 256. */ - TWO_FIFTY(16, 2); - - private final int distribution; - private final int length; - - SegmentSize(int distribution, int length) { - this.distribution = distribution; - this.length = length; - } - - /** - * @return the distribution size per character, i.e. how many possible outputs there are - * for any hexadecimal character - */ - public int getDistribution() { - return distribution; - } - - /** - * @return number of characters from a UUID that should be used to create a segment ID - */ - public int getLength() { - return length; - } - - /** - * @return number of segments to which this configuration will distribute all UUIDs - */ - public int getTotalSegments() { - return (int) Math.pow(distribution, length); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java b/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java deleted file mode 100644 index 6c12a171..00000000 --- a/src/main/java/fr/xephi/authme/datasource/AbstractSqlDataSource.java +++ /dev/null @@ -1,172 +0,0 @@ -package fr.xephi.authme.datasource; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; -import ch.jalu.datasourcecolumns.data.DataSourceValues; -import ch.jalu.datasourcecolumns.predicate.AlwaysTruePredicate; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumns; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; -import fr.xephi.authme.security.crypts.HashedPassword; - -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; - -import static ch.jalu.datasourcecolumns.data.UpdateValues.with; -import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eq; -import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eqIgnoreCase; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * Common type for SQL-based data sources. Classes implementing this - * must ensure that {@link #columnsHandler} is initialized on creation. - */ -public abstract class AbstractSqlDataSource implements DataSource { - - protected AuthMeColumnsHandler columnsHandler; - - @Override - public boolean isAuthAvailable(String user) { - try { - return columnsHandler.retrieve(user, AuthMeColumns.NAME).rowExists(); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - @Override - public HashedPassword getPassword(String user) { - try { - DataSourceValues values = columnsHandler.retrieve(user, AuthMeColumns.PASSWORD, AuthMeColumns.SALT); - if (values.rowExists()) { - return new HashedPassword(values.get(AuthMeColumns.PASSWORD), values.get(AuthMeColumns.SALT)); - } - } catch (SQLException e) { - logSqlException(e); - } - return null; - } - - @Override - public boolean saveAuth(PlayerAuth auth) { - return columnsHandler.insert(auth, - AuthMeColumns.NAME, AuthMeColumns.NICK_NAME, AuthMeColumns.PASSWORD, AuthMeColumns.SALT, - AuthMeColumns.EMAIL, AuthMeColumns.REGISTRATION_DATE, AuthMeColumns.REGISTRATION_IP, - AuthMeColumns.UUID); - } - - @Override - public boolean hasSession(String user) { - try { - DataSourceValue result = columnsHandler.retrieve(user, AuthMeColumns.HAS_SESSION); - return result.rowExists() && Integer.valueOf(1).equals(result.getValue()); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - @Override - public boolean updateSession(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); - } - - @Override - public boolean updatePassword(PlayerAuth auth) { - return updatePassword(auth.getNickname(), auth.getPassword()); - } - - @Override - public boolean updatePassword(String user, HashedPassword password) { - return columnsHandler.update(user, - with(AuthMeColumns.PASSWORD, password.getHash()) - .and(AuthMeColumns.SALT, password.getSalt()).build()); - } - - @Override - public boolean updateQuitLoc(PlayerAuth auth) { - return columnsHandler.update(auth, - AuthMeColumns.LOCATION_X, AuthMeColumns.LOCATION_Y, AuthMeColumns.LOCATION_Z, - AuthMeColumns.LOCATION_WORLD, AuthMeColumns.LOCATION_YAW, AuthMeColumns.LOCATION_PITCH); - } - - @Override - public List getAllAuthsByIp(String ip) { - try { - return columnsHandler.retrieve(eq(AuthMeColumns.LAST_IP, ip), AuthMeColumns.NAME); - } catch (SQLException e) { - logSqlException(e); - return Collections.emptyList(); - } - } - - @Override - public int countAuthsByEmail(String email) { - return columnsHandler.count(eqIgnoreCase(AuthMeColumns.EMAIL, email)); - } - - @Override - public boolean updateEmail(PlayerAuth auth) { - return columnsHandler.update(auth, AuthMeColumns.EMAIL); - } - - @Override - public boolean isLogged(String user) { - try { - DataSourceValue result = columnsHandler.retrieve(user, AuthMeColumns.IS_LOGGED); - return result.rowExists() && Integer.valueOf(1).equals(result.getValue()); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - @Override - public void setLogged(String user) { - columnsHandler.update(user, AuthMeColumns.IS_LOGGED, 1); - } - - @Override - public void setUnlogged(String user) { - columnsHandler.update(user, AuthMeColumns.IS_LOGGED, 0); - } - - @Override - public void grantSession(String user) { - columnsHandler.update(user, AuthMeColumns.HAS_SESSION, 1); - } - - @Override - public void revokeSession(String user) { - columnsHandler.update(user, AuthMeColumns.HAS_SESSION, 0); - } - - @Override - public void purgeLogged() { - columnsHandler.update(eq(AuthMeColumns.IS_LOGGED, 1), AuthMeColumns.IS_LOGGED, 0); - } - - @Override - public int getAccountsRegistered() { - return columnsHandler.count(new AlwaysTruePredicate<>()); - } - - @Override - public boolean updateRealName(String user, String realName) { - return columnsHandler.update(user, AuthMeColumns.NICK_NAME, realName); - } - - @Override - public DataSourceValue getEmail(String user) { - try { - return columnsHandler.retrieve(user, AuthMeColumns.EMAIL); - } catch (SQLException e) { - logSqlException(e); - return DataSourceValueImpl.unknownRow(); - } - } - - abstract String getJdbcUrl(String host, String port, String database); -} diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java deleted file mode 100644 index 450fd051..00000000 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ /dev/null @@ -1,323 +0,0 @@ -package fr.xephi.authme.datasource; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import ch.jalu.datasourcecolumns.data.DataSourceValueImpl; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.Utils; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -public class CacheDataSource implements DataSource { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(CacheDataSource.class); - private final DataSource source; - private final PlayerCache playerCache; - private final LoadingCache> cachedAuths; - private ListeningExecutorService executorService; - - /** - * Constructor for CacheDataSource. - * - * @param source the source - * @param playerCache the player cache - */ - public CacheDataSource(DataSource source, PlayerCache playerCache) { - this.source = source; - this.playerCache = playerCache; - if (AuthMe.settings.getProperty(DatabaseSettings.USE_VIRTUAL_THREADS)) { - try { - Method method = Executors.class.getMethod("newVirtualThreadPerTaskExecutor"); - method.setAccessible(true); - ExecutorService ex = (ExecutorService) method.invoke(null); - executorService = MoreExecutors.listeningDecorator(ex); - logger.info("Using virtual threads for cache loader"); - } catch (Exception e) { - executorService = MoreExecutors.listeningDecorator( - Executors.newCachedThreadPool(new ThreadFactoryBuilder() - .setDaemon(true) - .setNameFormat("AuthMe-CacheLoader") - .build()) - ); - logger.info("Cannot enable virtual threads, fallback to CachedThreadPool"); - } - } else { - executorService = MoreExecutors.listeningDecorator( - Executors.newCachedThreadPool(new ThreadFactoryBuilder() - .setDaemon(true) - .setNameFormat("AuthMe-CacheLoader") - .build()) - ); - } - cachedAuths = CacheBuilder.newBuilder() - .refreshAfterWrite(5, TimeUnit.MINUTES) - .expireAfterAccess(15, TimeUnit.MINUTES) - .build(new CacheLoader>() { - @Override - public Optional load(String key) { - return Optional.ofNullable(source.getAuth(key)); - } - - @Override - public ListenableFuture> reload(final String key, Optional oldValue) { - return executorService.submit(() -> load(key)); - } - }); - } - - public LoadingCache> getCachedAuths() { - return cachedAuths; - } - - @Override - public void reload() { - source.reload(); - } - - @Override - public boolean isCached() { - return true; - } - - @Override - public boolean isAuthAvailable(String user) { - return getAuth(user) != null; - } - - @Override - public HashedPassword getPassword(String user) { - user = user.toLowerCase(Locale.ROOT); - Optional pAuthOpt = cachedAuths.getIfPresent(user); - if (pAuthOpt != null && pAuthOpt.isPresent()) { - return pAuthOpt.get().getPassword(); - } - return source.getPassword(user); - } - - @Override - public PlayerAuth getAuth(String user) { - user = user.toLowerCase(Locale.ROOT); - return cachedAuths.getUnchecked(user).orElse(null); - } - - @Override - public boolean saveAuth(PlayerAuth auth) { - boolean result = source.saveAuth(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - - @Override - public boolean updatePassword(PlayerAuth auth) { - boolean result = source.updatePassword(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - - @Override - public boolean updatePassword(String user, HashedPassword password) { - user = user.toLowerCase(Locale.ROOT); - boolean result = source.updatePassword(user, password); - if (result) { - cachedAuths.refresh(user); - } - return result; - } - - @Override - public boolean updateSession(PlayerAuth auth) { - boolean result = source.updateSession(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - - @Override - public boolean updateQuitLoc(final PlayerAuth auth) { - boolean result = source.updateQuitLoc(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - - @Override - public Set getRecordsToPurge(long until) { - return source.getRecordsToPurge(until); - } - - @Override - public boolean removeAuth(String name) { - name = name.toLowerCase(Locale.ROOT); - boolean result = source.removeAuth(name); - if (result) { - cachedAuths.invalidate(name); - } - return result; - } - - @Override - public void closeConnection() { - executorService.shutdown(); - try { - executorService.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - logger.logException("Could not close executor service:", e); - } - cachedAuths.invalidateAll(); - source.closeConnection(); - } - - @Override - public boolean updateEmail(final PlayerAuth auth) { - boolean result = source.updateEmail(auth); - if (result) { - cachedAuths.refresh(auth.getNickname()); - } - return result; - } - - @Override - public List getAllAuthsByIp(String ip) { - return source.getAllAuthsByIp(ip); - } - - @Override - public int countAuthsByEmail(String email) { - return source.countAuthsByEmail(email); - } - - @Override - public void purgeRecords(Collection banned) { - source.purgeRecords(banned); - cachedAuths.invalidateAll(banned); - } - - @Override - public DataSourceType getType() { - return source.getType(); - } - - @Override - public boolean isLogged(String user) { - return source.isLogged(user); - } - - @Override - public void setLogged(final String user) { - source.setLogged(user.toLowerCase(Locale.ROOT)); - } - - @Override - public void setUnlogged(final String user) { - source.setUnlogged(user.toLowerCase(Locale.ROOT)); - } - - @Override - public boolean hasSession(final String user) { - return source.hasSession(user); - } - - @Override - public void grantSession(final String user) { - source.grantSession(user); - } - - @Override - public void revokeSession(final String user) { - source.revokeSession(user); - } - - @Override - public void purgeLogged() { - source.purgeLogged(); - cachedAuths.invalidateAll(); - } - - @Override - public int getAccountsRegistered() { - return source.getAccountsRegistered(); - } - - @Override - public boolean updateRealName(String user, String realName) { - boolean result = source.updateRealName(user, realName); - if (result) { - cachedAuths.refresh(user); - } - return result; - } - - @Override - public DataSourceValue getEmail(String user) { - return cachedAuths.getUnchecked(user) - .map(auth -> DataSourceValueImpl.of(auth.getEmail())) - .orElse(DataSourceValueImpl.unknownRow()); - } - - @Override - public List getAllAuths() { - return source.getAllAuths(); - } - - @Override - public List getLoggedPlayersWithEmptyMail() { - return playerCache.getCache().values().stream() - .filter(auth -> Utils.isEmailEmpty(auth.getEmail())) - .map(PlayerAuth::getRealName) - .collect(Collectors.toList()); - } - - @Override - public List getRecentlyLoggedInPlayers() { - return source.getRecentlyLoggedInPlayers(); - } - - @Override - public boolean setTotpKey(String user, String totpKey) { - boolean result = source.setTotpKey(user, totpKey); - if (result) { - cachedAuths.refresh(user); - } - return result; - } - - @Override - public void invalidateCache(String playerName) { - cachedAuths.invalidate(playerName); - } - - @Override - public void refreshCache(String playerName) { - if (cachedAuths.getIfPresent(playerName) != null) { - cachedAuths.refresh(playerName); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/Columns.java b/src/main/java/fr/xephi/authme/datasource/Columns.java deleted file mode 100644 index a604d0a4..00000000 --- a/src/main/java/fr/xephi/authme/datasource/Columns.java +++ /dev/null @@ -1,59 +0,0 @@ -package fr.xephi.authme.datasource; - -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -/** - * Database column names. - */ -// Justification: String is immutable and this class is used to easily access the configurable column names -@SuppressWarnings({"checkstyle:VisibilityModifier", "checkstyle:MemberName", "checkstyle:AbbreviationAsWordInName"}) -public final class Columns { - - public final String NAME; - public final String REAL_NAME; - public final String PASSWORD; - public final String SALT; - public final String TOTP_KEY; - public final String LAST_IP; - public final String LAST_LOGIN; - public final String GROUP; - public final String LASTLOC_X; - public final String LASTLOC_Y; - public final String LASTLOC_Z; - public final String LASTLOC_WORLD; - public final String LASTLOC_YAW; - public final String LASTLOC_PITCH; - public final String EMAIL; - public final String ID; - public final String IS_LOGGED; - public final String HAS_SESSION; - public final String REGISTRATION_DATE; - public final String REGISTRATION_IP; - public final String PLAYER_UUID; - - public Columns(Settings settings) { - NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); - REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME); - PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD); - SALT = settings.getProperty(DatabaseSettings.MYSQL_COL_SALT); - TOTP_KEY = settings.getProperty(DatabaseSettings.MYSQL_COL_TOTP_KEY); - LAST_IP = settings.getProperty(DatabaseSettings.MYSQL_COL_LAST_IP); - LAST_LOGIN = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOGIN); - GROUP = settings.getProperty(DatabaseSettings.MYSQL_COL_GROUP); - LASTLOC_X = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_X); - LASTLOC_Y = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Y); - LASTLOC_Z = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Z); - LASTLOC_WORLD = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_WORLD); - LASTLOC_YAW = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_YAW); - LASTLOC_PITCH = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_PITCH); - EMAIL = settings.getProperty(DatabaseSettings.MYSQL_COL_EMAIL); - ID = settings.getProperty(DatabaseSettings.MYSQL_COL_ID); - IS_LOGGED = settings.getProperty(DatabaseSettings.MYSQL_COL_ISLOGGED); - HAS_SESSION = settings.getProperty(DatabaseSettings.MYSQL_COL_HASSESSION); - REGISTRATION_DATE = settings.getProperty(DatabaseSettings.MYSQL_COL_REGISTER_DATE); - REGISTRATION_IP = settings.getProperty(DatabaseSettings.MYSQL_COL_REGISTER_IP); - PLAYER_UUID = settings.getProperty(DatabaseSettings.MYSQL_COL_PLAYER_UUID); - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java deleted file mode 100644 index 3152eb17..00000000 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ /dev/null @@ -1,286 +0,0 @@ -package fr.xephi.authme.datasource; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.security.crypts.HashedPassword; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -/** - * Interface for manipulating {@link PlayerAuth} objects from a data source. - */ -public interface DataSource extends Reloadable { - - /** - * Return whether the data source is cached and needs to send plugin messaging updates. - * - * @return true if the data source is cached. - */ - default boolean isCached() { - return false; - } - - /** - * Return whether there is a record for the given username. - * - * @param user The username to look up - * @return True if there is a record, false otherwise - */ - boolean isAuthAvailable(String user); - - /** - * Return the hashed password of the player. - * - * @param user The user whose password should be retrieve - * @return The password hash of the player - */ - HashedPassword getPassword(String user); - - /** - * Retrieve the entire PlayerAuth object associated with the username. - * - * @param user The user to retrieve - * @return The PlayerAuth object for the given username - */ - PlayerAuth getAuth(String user); - - /** - * Save a new PlayerAuth object. - * - * @param auth The new PlayerAuth to persist - * @return True upon success, false upon failure - */ - boolean saveAuth(PlayerAuth auth); - - /** - * Update the session of a record (IP, last login, real name). - * - * @param auth The PlayerAuth object to update in the database - * @return True upon success, false upon failure - */ - boolean updateSession(PlayerAuth auth); - - /** - * Update the password of the given PlayerAuth object. - * - * @param auth The PlayerAuth whose password should be updated - * @return True upon success, false upon failure - */ - boolean updatePassword(PlayerAuth auth); - - /** - * Update the password of the given player. - * - * @param user The user whose password should be updated - * @param password The new password - * @return True upon success, false upon failure - */ - boolean updatePassword(String user, HashedPassword password); - - /** - * Get all records in the database whose last login was before the given time. - * - * @param until The minimum last login - * @return The account names selected to purge - */ - Set getRecordsToPurge(long until); - - /** - * Purge the given players from the database. - * - * @param toPurge The players to purge - */ - void purgeRecords(Collection toPurge); - - /** - * Remove a user record from the database. - * - * @param user The user to remove - * @return True upon success, false upon failure - */ - boolean removeAuth(String user); - - /** - * Update the quit location of a PlayerAuth. - * - * @param auth The entry whose quit location should be updated - * @return True upon success, false upon failure - */ - boolean updateQuitLoc(PlayerAuth auth); - - /** - * Return all usernames associated with the given IP address. - * - * @param ip The IP address to look up - * @return Usernames associated with the given IP address - */ - List getAllAuthsByIp(String ip); - - /** - * Return the number of accounts associated with the given email address. - * - * @param email The email address to look up - * @return Number of accounts using the given email address - */ - int countAuthsByEmail(String email); - - /** - * Update the email of the PlayerAuth in the data source. - * - * @param auth The PlayerAuth whose email should be updated - * @return True upon success, false upon failure - */ - boolean updateEmail(PlayerAuth auth); - - /** - * Close the underlying connections to the data source. - */ - void closeConnection(); - - /** - * Return the data source type. - * - * @return the data source type - */ - DataSourceType getType(); - - /** - * Query the datasource whether the player is logged in or not. - * - * @param user The name of the player to verify - * @return True if logged in, false otherwise - */ - boolean isLogged(String user); - - /** - * Set a player as logged in. - * - * @param user The name of the player to change - */ - void setLogged(String user); - - /** - * Set a player as unlogged (not logged in). - * - * @param user The name of the player to change - */ - void setUnlogged(String user); - - /** - * Query the datasource whether the player has an active session or not. - * Warning: this value won't expire, you have also to check the user's last login timestamp. - * - * @param user The name of the player to verify - * @return True if the user has a valid session, false otherwise - */ - boolean hasSession(String user); - - /** - * Mark the user's hasSession value to true. - * - * @param user The name of the player to change - */ - void grantSession(String user); - - /** - * Mark the user's hasSession value to false. - * - * @param user The name of the player to change - */ - void revokeSession(String user); - - /** - * Set all players who are marked as logged in as NOT logged in. - */ - void purgeLogged(); - - /** - * Return all players which are logged in and whose email is not set. - * - * @return logged in players with no email - */ - List getLoggedPlayersWithEmptyMail(); - - /** - * Return the number of registered accounts. - * - * @return Total number of accounts - */ - int getAccountsRegistered(); - - /** - * Update a player's real name (capitalization). - * - * @param user The name of the user (lowercase) - * @param realName The real name of the user (proper casing) - * @return True upon success, false upon failure - */ - boolean updateRealName(String user, String realName); - - /** - * Returns the email of the user. - * - * @param user the user to retrieve an email for - * @return the email saved for the user, or null if user or email is not present - */ - DataSourceValue getEmail(String user); - - /** - * Return all players of the database. - * - * @return List of all players - */ - List getAllAuths(); - - /** - * Returns the last ten players who have recently logged in (first ten players with highest last login date). - * - * @return the 10 last players who last logged in - */ - List getRecentlyLoggedInPlayers(); - - /** - * Sets the given TOTP key to the player's account. - * - * @param user the name of the player to modify - * @param totpKey the totp key to set - * @return True upon success, false upon failure - */ - boolean setTotpKey(String user, String totpKey); - - /** - * Removes the TOTP key if present of the given player's account. - * - * @param user the name of the player to modify - * @return True upon success, false upon failure - */ - default boolean removeTotpKey(String user) { - return setTotpKey(user, null); - } - - /** - * Reload the data source. - */ - @Override - void reload(); - - /** - * Invalidate any cached data related to the specified player name. - * - * @param playerName the player name - */ - default void invalidateCache(String playerName) { - } - - /** - * Refresh any cached data (if present) related to the specified player name. - * - * @param playerName the player name - */ - default void refreshCache(String playerName) { - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/DataSourceType.java b/src/main/java/fr/xephi/authme/datasource/DataSourceType.java deleted file mode 100644 index f36faba7..00000000 --- a/src/main/java/fr/xephi/authme/datasource/DataSourceType.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.datasource; - -/** - * DataSource type. - */ -public enum DataSourceType { - H2, - - MYSQL, - - MARIADB, - - POSTGRESQL, - - SQLITE - -} diff --git a/src/main/java/fr/xephi/authme/datasource/H2.java b/src/main/java/fr/xephi/authme/datasource/H2.java deleted file mode 100644 index 94b28f58..00000000 --- a/src/main/java/fr/xephi/authme/datasource/H2.java +++ /dev/null @@ -1,422 +0,0 @@ -package fr.xephi.authme.datasource; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import java.io.File; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * H2 data source. - */ -@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore -public class H2 extends AbstractSqlDataSource { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(H2.class); - private final Settings settings; - private final File dataFolder; - private final String database; - private final String tableName; - private final Columns col; - private Connection con; - - /** - * Constructor for H2. - * - * @param settings The settings instance - * @param dataFolder The data folder - * @throws SQLException when initialization of a SQL datasource failed - */ - public H2(Settings settings, File dataFolder) throws SQLException { - this.settings = settings; - this.dataFolder = dataFolder; - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.col = new Columns(settings); - - try { - this.connect(); - this.setup(); - } catch (Exception ex) { - logger.logException("Error during H2 initialization:", ex); - throw ex; - } - } - - @VisibleForTesting - H2(Settings settings, File dataFolder, Connection connection) { - this.settings = settings; - this.dataFolder = dataFolder; - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.col = new Columns(settings); - this.con = connection; - this.columnsHandler = AuthMeColumnsHandler.createForH2(con, settings); - } - - /** - * Initializes the connection to the H2 database. - * - * @throws SQLException when an SQL error occurs while connecting - */ - protected void connect() throws SQLException { - try { - Class.forName("org.h2.Driver"); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Failed to load H2 JDBC class", e); - } - - logger.debug("H2 driver loaded"); - this.con = DriverManager.getConnection(this.getJdbcUrl(this.dataFolder.getAbsolutePath(), "", this.database)); - this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); - } - - /** - * Creates the table if necessary, or adds any missing columns to the table. - * - * @throws SQLException when an SQL error occurs while initializing the database - */ - @VisibleForTesting - @SuppressWarnings("checkstyle:CyclomaticComplexity") - protected void setup() throws SQLException { - try (Statement st = con.createStatement()) { - // Note: cannot add unique fields later on in SQLite, so we add it on initialization - st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" - + col.ID + " INTEGER AUTO_INCREMENT, " - + col.NAME + " VARCHAR(255) NOT NULL UNIQUE, " - + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));"); - - DatabaseMetaData md = con.getMetaData(); - - if (isColumnMissing(md, col.REAL_NAME)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " - + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';"); - } - - if (isColumnMissing(md, col.PASSWORD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';"); - } - - if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " + col.SALT + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.LAST_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.LAST_IP + " VARCHAR(40);"); - } - - if (isColumnMissing(md, col.LAST_LOGIN)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.LAST_LOGIN + " BIGINT;"); - } - - if (isColumnMissing(md, col.REGISTRATION_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.REGISTRATION_IP + " VARCHAR(40);"); - } - - if (isColumnMissing(md, col.REGISTRATION_DATE)) { - addRegistrationDateColumn(st); - } - - if (isColumnMissing(md, col.LASTLOC_X)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " + col.LASTLOC_X - + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " + col.LASTLOC_Y - + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " + col.LASTLOC_Z - + " DOUBLE NOT NULL DEFAULT '0.0';"); - } - - if (isColumnMissing(md, col.LASTLOC_WORLD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';"); - } - - if (isColumnMissing(md, col.LASTLOC_YAW)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " - + col.LASTLOC_YAW + " FLOAT;"); - } - - if (isColumnMissing(md, col.LASTLOC_PITCH)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN IF NOT EXISTS " - + col.LASTLOC_PITCH + " FLOAT;"); - } - - if (isColumnMissing(md, col.EMAIL)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.EMAIL + " VARCHAR_IGNORECASE(255);"); - } - - if (isColumnMissing(md, col.IS_LOGGED)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.IS_LOGGED + " INT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.HAS_SESSION)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.HAS_SESSION + " INT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.TOTP_KEY)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.TOTP_KEY + " VARCHAR(32);"); - } - - if (!col.PLAYER_UUID.isEmpty() && isColumnMissing(md, col.PLAYER_UUID)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.PLAYER_UUID + " VARCHAR(36)"); - } - } - logger.info("H2 Setup finished"); - } - - /** - * Checks if a column is missing in the specified table. - * @param columnName the name of the column to look for - * @return true if the column is missing, false if it exists - * @throws SQLException if an error occurs while executing SQL or accessing the result set - * @deprecated Not work in H2, it always returns true - */ - @Deprecated - private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { - String query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME = ?"; -// try (PreparedStatement preparedStatement = con.prepareStatement(query)) { -// preparedStatement.setString(1, tableName); -// preparedStatement.setString(2, columnName.toUpperCase()); -// try (ResultSet rs = preparedStatement.executeQuery()) { -// return !rs.next(); -// } -// } - return true; - } - - - @Override - public void reload() { - close(con); - try { - this.connect(); - this.setup(); - } catch (SQLException ex) { - logger.logException("Error while reloading H2:", ex); - } - } - - @Override - public PlayerAuth getAuth(String user) { - String sql = "SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return buildAuthFromResultSet(rs); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - - @Override - public Set getRecordsToPurge(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE MAX(" - + " COALESCE(" + col.LAST_LOGIN + ", 0)," - + " COALESCE(" + col.REGISTRATION_DATE + ", 0)" - + ") < ?;"; - try (PreparedStatement selectPst = con.prepareStatement(select)) { - selectPst.setLong(1, until); - try (ResultSet rs = selectPst.executeQuery()) { - while (rs.next()) { - list.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - - return list; - } - - @Override - public void purgeRecords(Collection toPurge) { - String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement deletePst = con.prepareStatement(delete)) { - for (String name : toPurge) { - deletePst.setString(1, name.toLowerCase(Locale.ROOT)); - deletePst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public boolean removeAuth(String user) { - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void closeConnection() { - try { - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public DataSourceType getType() { - return DataSourceType.H2; - } - - @Override - public List getAllAuths() { - List auths = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + ";"; - try (PreparedStatement pst = con.prepareStatement(sql); ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - PlayerAuth auth = buildAuthFromResultSet(rs); - auths.add(auth); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return auths; - } - - @Override - public List getLoggedPlayersWithEmptyMail() { - List players = new ArrayList<>(); - String sql = "SELECT " + col.REAL_NAME + " FROM " + tableName + " WHERE " + col.IS_LOGGED + " = 1" - + " AND (" + col.EMAIL + " = 'your@email.com' OR " + col.EMAIL + " IS NULL);"; - try (Statement st = con.createStatement(); ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(rs.getString(1)); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return players; - } - - @Override - public List getRecentlyLoggedInPlayers() { - List players = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; - try (Statement st = con.createStatement(); ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(buildAuthFromResultSet(rs)); - } - } catch (SQLException e) { - logSqlException(e); - } - return players; - } - - - @Override - public boolean setTotpKey(String user, String totpKey) { - String sql = "UPDATE " + tableName + " SET " + col.TOTP_KEY + " = ? WHERE " + col.NAME + " = ?"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, totpKey); - pst.setString(2, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException e) { - logSqlException(e); - } - return false; - } - - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { - String salt = !col.SALT.isEmpty() ? row.getString(col.SALT) : null; - - return PlayerAuth.builder() - .name(row.getString(col.NAME)) - .email(row.getString(col.EMAIL)) - .realName(row.getString(col.REAL_NAME)) - .password(row.getString(col.PASSWORD), salt) - .totpKey(row.getString(col.TOTP_KEY)) - .lastLogin(getNullableLong(row, col.LAST_LOGIN)) - .lastIp(row.getString(col.LAST_IP)) - .registrationDate(row.getLong(col.REGISTRATION_DATE)) - .registrationIp(row.getString(col.REGISTRATION_IP)) - .locX(row.getDouble(col.LASTLOC_X)) - .locY(row.getDouble(col.LASTLOC_Y)) - .locZ(row.getDouble(col.LASTLOC_Z)) - .locWorld(row.getString(col.LASTLOC_WORLD)) - .locYaw(row.getFloat(col.LASTLOC_YAW)) - .locPitch(row.getFloat(col.LASTLOC_PITCH)) - .build(); - } - - /** - * Creates the column for registration date and sets all entries to the current timestamp. - * We do so in order to avoid issues with purging, where entries with 0 / NULL might get - * purged immediately on startup otherwise. - * - * @param st Statement object to the database - */ - private void addRegistrationDateColumn(Statement st) throws SQLException { - int affect = st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN IF NOT EXISTS " + col.REGISTRATION_DATE + " BIGINT NOT NULL DEFAULT '0';"); - if (affect > 0) { - long currentTimestamp = System.currentTimeMillis(); - int updatedRows = st.executeUpdate(String.format("UPDATE %s SET %s = %d;", - tableName, col.REGISTRATION_DATE, currentTimestamp)); - logger.info("Created column '" + col.REGISTRATION_DATE + "' and set the current timestamp, " - + currentTimestamp + ", to all " + updatedRows + " rows"); - } - } - - @Override - String getJdbcUrl(String dataPath, String ignored, String database) { - return "jdbc:h2:" + dataPath + File.separator + database; - } - - private static void close(Connection con) { - if (con != null) { - try { - con.close(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - } -} - diff --git a/src/main/java/fr/xephi/authme/datasource/MariaDB.java b/src/main/java/fr/xephi/authme/datasource/MariaDB.java deleted file mode 100644 index 8fa35595..00000000 --- a/src/main/java/fr/xephi/authme/datasource/MariaDB.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.xephi.authme.datasource; - -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.settings.Settings; - -import java.sql.SQLException; - -public class MariaDB extends MySQL { - public MariaDB(Settings settings, MySqlExtensionsFactory extensionsFactory) throws SQLException { - super(settings, extensionsFactory); - } - - @Override - String getJdbcUrl(String host, String port, String database) { - return "jdbc:mariadb://" + host + ":" + port + "/" + database; - } - - @Override - protected String getDriverClassName() { - return "org.mariadb.jdbc.Driver"; - } - - @Override - public DataSourceType getType() { - return DataSourceType.MARIADB; - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java deleted file mode 100644 index 9a1cf216..00000000 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ /dev/null @@ -1,524 +0,0 @@ -package fr.xephi.authme.datasource; - -import com.google.common.annotations.VisibleForTesting; -import com.zaxxer.hikari.HikariDataSource; -import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.util.UuidUtils; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.UUID; - -import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * MySQL data source. - */ -@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore -public class MySQL extends AbstractSqlDataSource { - private final ConsoleLogger logger = ConsoleLoggerFactory.get(MySQL.class); - - private boolean useSsl; - private boolean serverCertificateVerification; - private boolean allowPublicKeyRetrieval; - private String mariaDbSslMode; - private String host; - private String port; - private String username; - private String password; - private String database; - private String tableName; - private int poolSize; - private int maxLifetime; - private List columnOthers; - private Columns col; - private MySqlExtension sqlExtension; - private HikariDataSource ds; - - public MySQL(Settings settings, MySqlExtensionsFactory extensionsFactory) throws SQLException { - setParameters(settings, extensionsFactory); - - // Set the connection arguments (and check if connection is ok) - try { - this.setConnectionArguments(); - } catch (RuntimeException e) { - if (e instanceof IllegalArgumentException) { - logger.warning("Invalid database arguments! Please check your configuration!"); - logger.warning("If this error persists, please report it to the developer!"); - } - if (e instanceof PoolInitializationException) { - logger.warning("Can't initialize database connection! Please check your configuration!"); - logger.warning("If this error persists, please report it to the developer!"); - } - logger.warning("Can't use the Hikari Connection Pool! Please, report this error to the developer!"); - throw e; - } - - // Initialize the database - try { - checkTablesAndColumns(); - } catch (SQLException e) { - closeConnection(); - logger.logException("Can't initialize the MySQL database:", e); - logger.warning("Please check your database settings in the config.yml file!"); - throw e; - } - } - - @VisibleForTesting - MySQL(Settings settings, HikariDataSource hikariDataSource, MySqlExtensionsFactory extensionsFactory) { - ds = hikariDataSource; - setParameters(settings, extensionsFactory); - } - - /** - * Returns the path of the Driver class to use when connecting to the database. - * - * @return the dotted path of the SQL driver class to be used - */ - protected String getDriverClassName() { - return "com.mysql.cj.jdbc.Driver"; - } - - /** - * Retrieves various settings. - * - * @param settings the settings to read properties from - * @param extensionsFactory factory to create the MySQL extension - */ - private void setParameters(Settings settings, MySqlExtensionsFactory extensionsFactory) { - this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); - this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); - this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); - this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD); - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); - this.col = new Columns(settings); - this.columnsHandler = AuthMeColumnsHandler.createForMySql(this::getConnection, settings); - this.sqlExtension = extensionsFactory.buildExtension(col); - this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); - this.maxLifetime = settings.getProperty(DatabaseSettings.MYSQL_CONNECTION_MAX_LIFETIME); - this.useSsl = settings.getProperty(DatabaseSettings.MYSQL_USE_SSL); - this.serverCertificateVerification = settings.getProperty(DatabaseSettings.MYSQL_CHECK_SERVER_CERTIFICATE); - this.allowPublicKeyRetrieval = settings.getProperty(DatabaseSettings.MYSQL_ALLOW_PUBLIC_KEY_RETRIEVAL); - this.mariaDbSslMode = settings.getProperty(DatabaseSettings.MARIADB_SSL_MODE); - } - - /** - * Sets up the connection arguments to the database. - */ - private void setConnectionArguments() { - ds = new HikariDataSource(); - ds.setPoolName("AuthMeMYSQLPool"); - - // Pool Settings - ds.setMaximumPoolSize(poolSize); - ds.setMaxLifetime(maxLifetime * 1000L); - - // Database URL - ds.setJdbcUrl(this.getJdbcUrl(this.host, this.port, this.database)); - - // Auth - ds.setUsername(this.username); - ds.setPassword(this.password); - - // Driver - ds.setDriverClassName(this.getDriverClassName()); - - // Request mysql over SSL - if (this instanceof MariaDB) { - ds.addDataSourceProperty("sslMode", mariaDbSslMode); - } else { - ds.addDataSourceProperty("useSSL", String.valueOf(useSsl)); - - // Disabling server certificate verification on need - if (!serverCertificateVerification) { - ds.addDataSourceProperty("verifyServerCertificate", String.valueOf(false)); - } - } - - - // Disabling server certificate verification on need - if (allowPublicKeyRetrieval) { - ds.addDataSourceProperty("allowPublicKeyRetrieval", String.valueOf(true)); - } - - // Encoding - ds.addDataSourceProperty("characterEncoding", "utf8"); - ds.addDataSourceProperty("encoding", "UTF-8"); - ds.addDataSourceProperty("useUnicode", "true"); - - // Random stuff - ds.addDataSourceProperty("rewriteBatchedStatements", "true"); - ds.addDataSourceProperty("jdbcCompliantTruncation", "false"); - - // Caching - ds.addDataSourceProperty("cachePrepStmts", "true"); - ds.addDataSourceProperty("prepStmtCacheSize", "275"); - ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - - logger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); - } - - @Override - public void reload() { - if (ds != null) { - ds.close(); - } - setConnectionArguments(); - logger.info("Hikari ConnectionPool arguments reloaded!"); - } - - private Connection getConnection() throws SQLException { - return ds.getConnection(); - } - - /** - * Creates the table or any of its required columns if they don't exist. - */ - @SuppressWarnings({"checkstyle:CyclomaticComplexity", "checkstyle:JavaNCSS"}) - private void checkTablesAndColumns() throws SQLException { - try (Connection con = getConnection(); Statement st = con.createStatement()) { - // Create table with ID column if it doesn't exist - String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" - + col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT," - + "PRIMARY KEY (" + col.ID + ")" - + ") CHARACTER SET = utf8;"; - st.executeUpdate(sql); - - DatabaseMetaData md = con.getMetaData(); - if (isColumnMissing(md, col.NAME)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";"); - } - - if (isColumnMissing(md, col.REAL_NAME)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";"); - } - - if (isColumnMissing(md, col.PASSWORD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;"); - } - - if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.LAST_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin;"); - } else { - MySqlMigrater.migrateLastIpColumn(st, md, tableName, col); - } - - if (isColumnMissing(md, col.LAST_LOGIN)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_LOGIN + " BIGINT;"); - } else { - MySqlMigrater.migrateLastLoginColumn(st, md, tableName, col); - } - - if (isColumnMissing(md, col.REGISTRATION_DATE)) { - MySqlMigrater.addRegistrationDateColumn(st, tableName, col); - } - - if (isColumnMissing(md, col.REGISTRATION_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REGISTRATION_IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin;"); - } - - if (isColumnMissing(md, col.LASTLOC_X)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD " - + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_X + " , ADD " - + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y); - } else { - st.executeUpdate("ALTER TABLE " + tableName + " MODIFY " - + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY " - + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY " - + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';"); - } - - if (isColumnMissing(md, col.LASTLOC_WORLD)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z); - } - - if (isColumnMissing(md, col.LASTLOC_YAW)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_YAW + " FLOAT;"); - } - - if (isColumnMissing(md, col.LASTLOC_PITCH)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_PITCH + " FLOAT;"); - } - - if (isColumnMissing(md, col.EMAIL)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.EMAIL + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.IS_LOGGED)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL); - } - - if (isColumnMissing(md, col.HAS_SESSION)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.HAS_SESSION + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.IS_LOGGED); - } - - if (isColumnMissing(md, col.TOTP_KEY)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.TOTP_KEY + " VARCHAR(32);"); - } else if (SqlDataSourceUtils.getColumnSize(md, tableName, col.TOTP_KEY) != 32) { - st.executeUpdate("ALTER TABLE " + tableName - + " MODIFY " + col.TOTP_KEY + " VARCHAR(32);"); - } - - if (!col.PLAYER_UUID.isEmpty() && isColumnMissing(md, col.PLAYER_UUID)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PLAYER_UUID + " VARCHAR(36)"); - } - } - logger.info("MySQL setup finished"); - } - - private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(database, null, tableName, columnName)) { - return !rs.next(); - } - } - - @Override - public PlayerAuth getAuth(String user) { - String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;"; - PlayerAuth auth; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase(Locale.ROOT)); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - auth = buildAuthFromResultSet(rs); - sqlExtension.extendAuth(auth, id, con); - return auth; - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - - @Override - public boolean saveAuth(PlayerAuth auth) { - super.saveAuth(auth); - - try (Connection con = getConnection()) { - if (!columnOthers.isEmpty()) { - for (String column : columnOthers) { - try (PreparedStatement pst = con.prepareStatement( - "UPDATE " + tableName + " SET " + column + "=? WHERE " + col.NAME + "=?;")) { - pst.setString(1, auth.getRealName()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - } - } - } - - sqlExtension.saveAuth(auth, con); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - String getJdbcUrl(String host, String port, String database) { - return "jdbc:mysql://" + host + ":" + port + "/" + database; - } - - @Override - public Set getRecordsToPurge(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE GREATEST(" - + " COALESCE(" + col.LAST_LOGIN + ", 0)," - + " COALESCE(" + col.REGISTRATION_DATE + ", 0)" - + ") < ?;"; - try (Connection con = getConnection(); - PreparedStatement selectPst = con.prepareStatement(select)) { - selectPst.setLong(1, until); - try (ResultSet rs = selectPst.executeQuery()) { - while (rs.next()) { - list.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - - return list; - } - - @Override - public boolean removeAuth(String user) { - user = user.toLowerCase(Locale.ROOT); - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - sqlExtension.removeAuth(user, con); - pst.setString(1, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void closeConnection() { - if (ds != null && !ds.isClosed()) { - ds.close(); - } - } - - @Override - public void purgeRecords(Collection toPurge) { - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - for (String name : toPurge) { - pst.setString(1, name.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public DataSourceType getType() { - return DataSourceType.MYSQL; - } - - @Override - public List getAllAuths() { - List auths = new ArrayList<>(); - try (Connection con = getConnection(); Statement st = con.createStatement()) { - try (ResultSet rs = st.executeQuery("SELECT * FROM " + tableName)) { - while (rs.next()) { - PlayerAuth auth = buildAuthFromResultSet(rs); - sqlExtension.extendAuth(auth, rs.getInt(col.ID), con); - auths.add(auth); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return auths; - } - - @Override - public List getLoggedPlayersWithEmptyMail() { - List players = new ArrayList<>(); - String sql = "SELECT " + col.REAL_NAME + " FROM " + tableName + " WHERE " + col.IS_LOGGED + " = 1" - + " AND (" + col.EMAIL + " = 'your@email.com' OR " + col.EMAIL + " IS NULL);"; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(rs.getString(1)); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return players; - } - - @Override - public List getRecentlyLoggedInPlayers() { - List players = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(buildAuthFromResultSet(rs)); - } - } catch (SQLException e) { - logSqlException(e); - } - return players; - } - - @Override - public boolean setTotpKey(String user, String totpKey) { - String sql = "UPDATE " + tableName + " SET " + col.TOTP_KEY + " = ? WHERE " + col.NAME + " = ?"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, totpKey); - pst.setString(2, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException e) { - logSqlException(e); - } - return false; - } - - /** - * Creates a {@link PlayerAuth} object with the data from the provided result set. - * - * @param row the result set to read from - * @return generated player auth object with the data from the result set - * @throws SQLException . - */ - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { - String salt = col.SALT.isEmpty() ? null : row.getString(col.SALT); - int group = col.GROUP.isEmpty() ? -1 : row.getInt(col.GROUP); - UUID uuid = col.PLAYER_UUID.isEmpty() - ? null : UuidUtils.parseUuidSafely(row.getString(col.PLAYER_UUID)); - return PlayerAuth.builder() - .name(row.getString(col.NAME)) - .realName(row.getString(col.REAL_NAME)) - .password(row.getString(col.PASSWORD), salt) - .totpKey(row.getString(col.TOTP_KEY)) - .lastLogin(getNullableLong(row, col.LAST_LOGIN)) - .lastIp(row.getString(col.LAST_IP)) - .email(row.getString(col.EMAIL)) - .registrationDate(row.getLong(col.REGISTRATION_DATE)) - .registrationIp(row.getString(col.REGISTRATION_IP)) - .groupId(group) - .locWorld(row.getString(col.LASTLOC_WORLD)) - .locX(row.getDouble(col.LASTLOC_X)) - .locY(row.getDouble(col.LASTLOC_Y)) - .locZ(row.getDouble(col.LASTLOC_Z)) - .locYaw(row.getFloat(col.LASTLOC_YAW)) - .locPitch(row.getFloat(col.LASTLOC_PITCH)) - .uuid(uuid) - .build(); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/MySqlMigrater.java b/src/main/java/fr/xephi/authme/datasource/MySqlMigrater.java deleted file mode 100644 index fec564d5..00000000 --- a/src/main/java/fr/xephi/authme/datasource/MySqlMigrater.java +++ /dev/null @@ -1,116 +0,0 @@ -package fr.xephi.authme.datasource; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Types; - -/** - * Performs migrations on the MySQL data source if necessary. - */ -final class MySqlMigrater { - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(MySqlMigrater.class); - - private MySqlMigrater() { - } - - /** - * Changes the last IP column to be nullable if it has a NOT NULL constraint without a default value. - * Background: Before 5.2, the last IP column was initialized to be {@code NOT NULL} without a default. - * With the introduction of a registration IP column we no longer want to set the last IP column on registration. - * - * @param st Statement object to the database - * @param metaData column metadata for the table - * @param tableName the MySQL table's name - * @param col the column names configuration - */ - static void migrateLastIpColumn(Statement st, DatabaseMetaData metaData, - String tableName, Columns col) throws SQLException { - final boolean isNotNullWithoutDefault = SqlDataSourceUtils.isNotNullColumn(metaData, tableName, col.LAST_IP) - && SqlDataSourceUtils.getColumnDefaultValue(metaData, tableName, col.LAST_IP) == null; - - if (isNotNullWithoutDefault) { - String sql = String.format("ALTER TABLE %s MODIFY %s VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin", - tableName, col.LAST_IP); - st.execute(sql); - logger.info("Changed last login column to allow NULL values. Please verify the registration feature " - + "if you are hooking into a forum."); - } - } - - /** - * Checks if the last login column has a type that needs to be migrated. - * - * @param st Statement object to the database - * @param metaData column metadata for the table - * @param tableName the MySQL table's name - * @param col the column names configuration - */ - static void migrateLastLoginColumn(Statement st, DatabaseMetaData metaData, - String tableName, Columns col) throws SQLException { - final int columnType; - try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) { - if (!rs.next()) { - logger.warning("Could not get LAST_LOGIN meta data. This should never happen!"); - return; - } - columnType = rs.getInt("DATA_TYPE"); - } - - if (columnType == Types.INTEGER) { - migrateLastLoginColumnFromInt(st, tableName, col); - } - } - - /** - * Performs conversion of lastlogin column from int to bigint. - * - * @param st Statement object to the database - * @param tableName the table name - * @param col the column names configuration - * @see - * #887: Migrate lastlogin column from int32 to bigint - */ - private static void migrateLastLoginColumnFromInt(Statement st, String tableName, Columns col) throws SQLException { - // Change from int to bigint - logger.info("Migrating lastlogin column from int to bigint"); - String sql = String.format("ALTER TABLE %s MODIFY %s BIGINT;", tableName, col.LAST_LOGIN); - st.execute(sql); - - // Migrate timestamps in seconds format to milliseconds format if they are plausible - int rangeStart = 1262304000; // timestamp for 2010-01-01 - int rangeEnd = 1514678400; // timestamp for 2017-12-31 - sql = String.format("UPDATE %s SET %s = %s * 1000 WHERE %s > %d AND %s < %d;", - tableName, col.LAST_LOGIN, col.LAST_LOGIN, col.LAST_LOGIN, rangeStart, col.LAST_LOGIN, rangeEnd); - int changedRows = st.executeUpdate(sql); - - logger.warning("You may have entries with invalid timestamps. Please check your data " - + "before purging. " + changedRows + " rows were migrated from seconds to milliseconds."); - } - - /** - * Creates the column for registration date and sets all entries to the current timestamp. - * We do so in order to avoid issues with purging, where entries with 0 / NULL might get - * purged immediately on startup otherwise. - * - * @param st Statement object to the database - * @param tableName the table name - * @param col the column names configuration - */ - static void addRegistrationDateColumn(Statement st, String tableName, Columns col) throws SQLException { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REGISTRATION_DATE + " BIGINT NOT NULL DEFAULT 0;"); - - // Use the timestamp from Java to avoid timezone issues in case JVM and database are out of sync - long currentTimestamp = System.currentTimeMillis(); - int updatedRows = st.executeUpdate(String.format("UPDATE %s SET %s = %d;", - tableName, col.REGISTRATION_DATE, currentTimestamp)); - logger.info("Created column '" + col.REGISTRATION_DATE + "' and set the current timestamp, " - + currentTimestamp + ", to all " + updatedRows + " rows"); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/PostgreSqlDataSource.java b/src/main/java/fr/xephi/authme/datasource/PostgreSqlDataSource.java deleted file mode 100644 index cc308934..00000000 --- a/src/main/java/fr/xephi/authme/datasource/PostgreSqlDataSource.java +++ /dev/null @@ -1,472 +0,0 @@ -package fr.xephi.authme.datasource; - -import com.google.common.annotations.VisibleForTesting; -import com.zaxxer.hikari.HikariDataSource; -import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * PostgreSQL data source. - */ -public class PostgreSqlDataSource extends AbstractSqlDataSource { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PostgreSqlDataSource.class); - - private String host; - private String port; - private String username; - private String password; - private String database; - private String tableName; - private int poolSize; - private int maxLifetime; - private List columnOthers; - private Columns col; - private MySqlExtension sqlExtension; - private HikariDataSource ds; - - public PostgreSqlDataSource(Settings settings, MySqlExtensionsFactory extensionsFactory) throws SQLException { - setParameters(settings, extensionsFactory); - - // Set the connection arguments (and check if connection is ok) - try { - this.setConnectionArguments(); - } catch (RuntimeException e) { - if (e instanceof IllegalArgumentException) { - logger.warning("Invalid database arguments! Please check your configuration!"); - logger.warning("If this error persists, please report it to the developer!"); - } - if (e instanceof PoolInitializationException) { - logger.warning("Can't initialize database connection! Please check your configuration!"); - logger.warning("If this error persists, please report it to the developer!"); - } - logger.warning("Can't use the Hikari Connection Pool! Please, report this error to the developer!"); - throw e; - } - - // Initialize the database - try { - checkTablesAndColumns(); - } catch (SQLException e) { - closeConnection(); - logger.logException("Can't initialize the PostgreSQL database:", e); - logger.warning("Please check your database settings in the config.yml file!"); - throw e; - } - } - - @VisibleForTesting - PostgreSqlDataSource(Settings settings, HikariDataSource hikariDataSource, - MySqlExtensionsFactory extensionsFactory) { - ds = hikariDataSource; - setParameters(settings, extensionsFactory); - } - - /** - * Retrieves various settings. - * - * @param settings the settings to read properties from - * @param extensionsFactory factory to create the MySQL extension - */ - private void setParameters(Settings settings, MySqlExtensionsFactory extensionsFactory) { - this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); - this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); - this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); - this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD); - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); - this.col = new Columns(settings); - this.columnsHandler = AuthMeColumnsHandler.createForMySql(this::getConnection, settings); - this.sqlExtension = extensionsFactory.buildExtension(col); - this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); - this.maxLifetime = settings.getProperty(DatabaseSettings.MYSQL_CONNECTION_MAX_LIFETIME); - } - - /** - * Sets up the connection arguments to the database. - */ - private void setConnectionArguments() { - ds = new HikariDataSource(); - ds.setPoolName("AuthMePostgreSQLPool"); - - // Pool Settings - ds.setMaximumPoolSize(poolSize); - ds.setMaxLifetime(maxLifetime * 1000); - - // Database URL - ds.setDriverClassName("org.postgresql.Driver"); - ds.setJdbcUrl(this.getJdbcUrl(this.host, this.port, this.database)); - - // Auth - ds.setUsername(this.username); - ds.setPassword(this.password); - - // Random stuff - ds.addDataSourceProperty("reWriteBatchedInserts", "true"); - - // Caching - ds.addDataSourceProperty("cachePrepStmts", "true"); - ds.addDataSourceProperty("preparedStatementCacheQueries", "275"); - - logger.info("Connection arguments loaded, Hikari ConnectionPool ready!"); - } - - @Override - public void reload() { - if (ds != null) { - ds.close(); - } - setConnectionArguments(); - logger.info("Hikari ConnectionPool arguments reloaded!"); - } - - private Connection getConnection() throws SQLException { - return ds.getConnection(); - } - - /** - * Creates the table or any of its required columns if they don't exist. - */ - private void checkTablesAndColumns() throws SQLException { - try (Connection con = getConnection(); Statement st = con.createStatement()) { - // Create table with ID column if it doesn't exist - String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" - + col.ID + " BIGSERIAL," - + "PRIMARY KEY (" + col.ID + ")" - + ");"; - st.executeUpdate(sql); - - DatabaseMetaData md = con.getMetaData(); - if (isColumnMissing(md, col.NAME)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE;"); - } - - if (isColumnMissing(md, col.REAL_NAME)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL;"); - } - - if (isColumnMissing(md, col.PASSWORD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;"); - } - - if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.LAST_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_IP + " VARCHAR(40);"); - } else { - MySqlMigrater.migrateLastIpColumn(st, md, tableName, col); - } - - if (isColumnMissing(md, col.LAST_LOGIN)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_LOGIN + " BIGINT;"); - } else { - MySqlMigrater.migrateLastLoginColumn(st, md, tableName, col); - } - - if (isColumnMissing(md, col.REGISTRATION_DATE)) { - MySqlMigrater.addRegistrationDateColumn(st, tableName, col); - } - - if (isColumnMissing(md, col.REGISTRATION_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REGISTRATION_IP + " VARCHAR(40);"); - } - - if (isColumnMissing(md, col.LASTLOC_X)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_X + " DOUBLE PRECISION NOT NULL DEFAULT '0.0' , ADD " - + col.LASTLOC_Y + " DOUBLE PRECISION NOT NULL DEFAULT '0.0' , ADD " - + col.LASTLOC_Z + " DOUBLE PRECISION NOT NULL DEFAULT '0.0';"); - } - - if (isColumnMissing(md, col.LASTLOC_WORLD)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';"); - } - - if (isColumnMissing(md, col.LASTLOC_YAW)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_YAW + " FLOAT;"); - } - - if (isColumnMissing(md, col.LASTLOC_PITCH)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_PITCH + " FLOAT;"); - } - - if (isColumnMissing(md, col.EMAIL)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.EMAIL + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.IS_LOGGED)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.HAS_SESSION)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.HAS_SESSION + " SMALLINT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.TOTP_KEY)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.TOTP_KEY + " VARCHAR(32);"); - } else if (SqlDataSourceUtils.getColumnSize(md, tableName, col.TOTP_KEY) != 32) { - st.executeUpdate("ALTER TABLE " + tableName - + " ALTER COLUMN " + col.TOTP_KEY + " TYPE VARCHAR(32);"); - } - - if (!col.PLAYER_UUID.isEmpty() && isColumnMissing(md, col.PLAYER_UUID)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PLAYER_UUID + " VARCHAR(36)"); - } - } - logger.info("PostgreSQL setup finished"); - } - - private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName.toLowerCase(Locale.ROOT))) { - return !rs.next(); - } - } - - @Override - public PlayerAuth getAuth(String user) { - String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;"; - PlayerAuth auth; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase(Locale.ROOT)); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - int id = rs.getInt(col.ID); - auth = buildAuthFromResultSet(rs); - sqlExtension.extendAuth(auth, id, con); - return auth; - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - - @Override - public boolean saveAuth(PlayerAuth auth) { - super.saveAuth(auth); - - try (Connection con = getConnection()) { - if (!columnOthers.isEmpty()) { - for (String column : columnOthers) { - try (PreparedStatement pst = con.prepareStatement( - "UPDATE " + tableName + " SET " + column + "=? WHERE " + col.NAME + "=?;")) { - pst.setString(1, auth.getRealName()); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - } - } - } - - sqlExtension.saveAuth(auth, con); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - String getJdbcUrl(String host, String port, String database) { - return "jdbc:postgresql://" + host + ":" + port + "/" + database; - } - - @Override - public Set getRecordsToPurge(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE GREATEST(" - + " COALESCE(" + col.LAST_LOGIN + ", 0)," - + " COALESCE(" + col.REGISTRATION_DATE + ", 0)" - + ") < ?;"; - try (Connection con = getConnection(); - PreparedStatement selectPst = con.prepareStatement(select)) { - selectPst.setLong(1, until); - try (ResultSet rs = selectPst.executeQuery()) { - while (rs.next()) { - list.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - - return list; - } - - @Override - public boolean removeAuth(String user) { - user = user.toLowerCase(Locale.ROOT); - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - sqlExtension.removeAuth(user, con); - pst.setString(1, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void closeConnection() { - if (ds != null && !ds.isClosed()) { - ds.close(); - } - } - - @Override - public void purgeRecords(Collection toPurge) { - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - for (String name : toPurge) { - pst.setString(1, name.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public DataSourceType getType() { - return DataSourceType.POSTGRESQL; - } - - @Override - public List getAllAuths() { - List auths = new ArrayList<>(); - try (Connection con = getConnection(); Statement st = con.createStatement()) { - try (ResultSet rs = st.executeQuery("SELECT * FROM " + tableName)) { - while (rs.next()) { - PlayerAuth auth = buildAuthFromResultSet(rs); - sqlExtension.extendAuth(auth, rs.getInt(col.ID), con); - auths.add(auth); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return auths; - } - - @Override - public List getLoggedPlayersWithEmptyMail() { - List players = new ArrayList<>(); - String sql = "SELECT " + col.REAL_NAME + " FROM " + tableName + " WHERE " + col.IS_LOGGED + " = 1" - + " AND (" + col.EMAIL + " = 'your@email.com' OR " + col.EMAIL + " IS NULL);"; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(rs.getString(1)); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return players; - } - - @Override - public List getRecentlyLoggedInPlayers() { - List players = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(buildAuthFromResultSet(rs)); - } - } catch (SQLException e) { - logSqlException(e); - } - return players; - } - - @Override - public boolean setTotpKey(String user, String totpKey) { - String sql = "UPDATE " + tableName + " SET " + col.TOTP_KEY + " = ? WHERE " + col.NAME + " = ?"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, totpKey); - pst.setString(2, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException e) { - logSqlException(e); - } - return false; - } - - /** - * Creates a {@link PlayerAuth} object with the data from the provided result set. - * - * @param row the result set to read from - * - * @return generated player auth object with the data from the result set - * - * @throws SQLException . - */ - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { - String salt = col.SALT.isEmpty() ? null : row.getString(col.SALT); - int group = col.GROUP.isEmpty() ? -1 : row.getInt(col.GROUP); - return PlayerAuth.builder() - .name(row.getString(col.NAME)) - .realName(row.getString(col.REAL_NAME)) - .password(row.getString(col.PASSWORD), salt) - .totpKey(row.getString(col.TOTP_KEY)) - .lastLogin(getNullableLong(row, col.LAST_LOGIN)) - .lastIp(row.getString(col.LAST_IP)) - .email(row.getString(col.EMAIL)) - .registrationDate(row.getLong(col.REGISTRATION_DATE)) - .registrationIp(row.getString(col.REGISTRATION_IP)) - .groupId(group) - .locWorld(row.getString(col.LASTLOC_WORLD)) - .locX(row.getDouble(col.LASTLOC_X)) - .locY(row.getDouble(col.LASTLOC_Y)) - .locZ(row.getDouble(col.LASTLOC_Z)) - .locYaw(row.getFloat(col.LASTLOC_YAW)) - .locPitch(row.getFloat(col.LASTLOC_PITCH)) - .build(); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java deleted file mode 100644 index b261b5d5..00000000 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ /dev/null @@ -1,423 +0,0 @@ -package fr.xephi.authme.datasource; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.columnshandler.AuthMeColumnsHandler; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import java.io.File; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * SQLite data source. - */ -@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore -public class SQLite extends AbstractSqlDataSource { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(SQLite.class); - private final Settings settings; - private final File dataFolder; - private final String database; - private final String tableName; - private final Columns col; - private Connection con; - - /** - * Constructor for SQLite. - * - * @param settings The settings instance - * @param dataFolder The data folder - * - * @throws SQLException when initialization of a SQL datasource failed - */ - public SQLite(Settings settings, File dataFolder) throws SQLException { - this.settings = settings; - this.dataFolder = dataFolder; - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.col = new Columns(settings); - - try { - this.connect(); - this.setup(); - this.migrateIfNeeded(); - } catch (Exception ex) { - logger.logException("Error during SQLite initialization:", ex); - throw ex; - } - } - - @VisibleForTesting - SQLite(Settings settings, File dataFolder, Connection connection) { - this.settings = settings; - this.dataFolder = dataFolder; - this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.col = new Columns(settings); - this.con = connection; - this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); - } - - /** - * Initializes the connection to the SQLite database. - * - * @throws SQLException when an SQL error occurs while connecting - */ - protected void connect() throws SQLException { - try { - Class.forName("org.sqlite.JDBC"); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Failed to load SQLite JDBC class", e); - } - - logger.debug("SQLite driver loaded"); - this.con = DriverManager.getConnection(this.getJdbcUrl(this.dataFolder.getAbsolutePath(), "", this.database)); - this.columnsHandler = AuthMeColumnsHandler.createForSqlite(con, settings); - } - - /** - * Creates the table if necessary, or adds any missing columns to the table. - * - * @throws SQLException when an SQL error occurs while initializing the database - */ - @VisibleForTesting - @SuppressWarnings("checkstyle:CyclomaticComplexity") - protected void setup() throws SQLException { - try (Statement st = con.createStatement()) { - // Note: cannot add unique fields later on in SQLite, so we add it on initialization - st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" - + col.ID + " INTEGER AUTO_INCREMENT, " - + col.NAME + " VARCHAR(255) NOT NULL UNIQUE, " - + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));"); - - DatabaseMetaData md = con.getMetaData(); - - if (isColumnMissing(md, col.REAL_NAME)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';"); - } - - if (isColumnMissing(md, col.PASSWORD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';"); - } - - if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.LAST_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_IP + " VARCHAR(40);"); - } - - if (isColumnMissing(md, col.LAST_LOGIN)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;"); - } - - if (isColumnMissing(md, col.REGISTRATION_IP)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REGISTRATION_IP + " VARCHAR(40);"); - } - - if (isColumnMissing(md, col.REGISTRATION_DATE)) { - addRegistrationDateColumn(st); - } - - if (isColumnMissing(md, col.LASTLOC_X)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X - + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y - + " DOUBLE NOT NULL DEFAULT '0.0';"); - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z - + " DOUBLE NOT NULL DEFAULT '0.0';"); - } - - if (isColumnMissing(md, col.LASTLOC_WORLD)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';"); - } - - if (isColumnMissing(md, col.LASTLOC_YAW)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_YAW + " FLOAT;"); - } - - if (isColumnMissing(md, col.LASTLOC_PITCH)) { - st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " - + col.LASTLOC_PITCH + " FLOAT;"); - } - - if (isColumnMissing(md, col.EMAIL)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.EMAIL + " VARCHAR(255);"); - } - - if (isColumnMissing(md, col.IS_LOGGED)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.IS_LOGGED + " INT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.HAS_SESSION)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.HAS_SESSION + " INT NOT NULL DEFAULT '0';"); - } - - if (isColumnMissing(md, col.TOTP_KEY)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.TOTP_KEY + " VARCHAR(32);"); - } - - if (!col.PLAYER_UUID.isEmpty() && isColumnMissing(md, col.PLAYER_UUID)) { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.PLAYER_UUID + " VARCHAR(36)"); - } - } - logger.info("SQLite Setup finished"); - } - - /** - * Migrates the database if necessary. See {@link SqLiteMigrater} for details. - */ - @VisibleForTesting - void migrateIfNeeded() throws SQLException { - DatabaseMetaData metaData = con.getMetaData(); - if (SqLiteMigrater.isMigrationRequired(metaData, tableName, col)) { - new SqLiteMigrater(settings, dataFolder).performMigration(this); - // Migration deletes the table and recreates it, therefore call connect() again - // to get an up-to-date Connection to the database - connect(); - } - } - - private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { - return !rs.next(); - } - } - - @Override - public void reload() { - close(con); - try { - this.connect(); - this.setup(); - this.migrateIfNeeded(); - } catch (SQLException ex) { - logger.logException("Error while reloading SQLite:", ex); - } - } - - @Override - public PlayerAuth getAuth(String user) { - String sql = "SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return buildAuthFromResultSet(rs); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return null; - } - - @Override - public Set getRecordsToPurge(long until) { - Set list = new HashSet<>(); - String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE MAX(" - + " COALESCE(" + col.LAST_LOGIN + ", 0)," - + " COALESCE(" + col.REGISTRATION_DATE + ", 0)" - + ") < ?;"; - try (PreparedStatement selectPst = con.prepareStatement(select)) { - selectPst.setLong(1, until); - try (ResultSet rs = selectPst.executeQuery()) { - while (rs.next()) { - list.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - - return list; - } - - @Override - public void purgeRecords(Collection toPurge) { - String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement deletePst = con.prepareStatement(delete)) { - for (String name : toPurge) { - deletePst.setString(1, name.toLowerCase(Locale.ROOT)); - deletePst.executeUpdate(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public boolean removeAuth(String user) { - String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; - } - - @Override - public void closeConnection() { - try { - if (con != null && !con.isClosed()) { - con.close(); - } - } catch (SQLException ex) { - logSqlException(ex); - } - } - - @Override - public DataSourceType getType() { - return DataSourceType.SQLITE; - } - - @Override - public List getAllAuths() { - List auths = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + ";"; - try (PreparedStatement pst = con.prepareStatement(sql); ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - PlayerAuth auth = buildAuthFromResultSet(rs); - auths.add(auth); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return auths; - } - - @Override - public List getLoggedPlayersWithEmptyMail() { - List players = new ArrayList<>(); - String sql = "SELECT " + col.REAL_NAME + " FROM " + tableName + " WHERE " + col.IS_LOGGED + " = 1" - + " AND (" + col.EMAIL + " = 'your@email.com' OR " + col.EMAIL + " IS NULL);"; - try (Statement st = con.createStatement(); ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(rs.getString(1)); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return players; - } - - @Override - public List getRecentlyLoggedInPlayers() { - List players = new ArrayList<>(); - String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; - try (Statement st = con.createStatement(); ResultSet rs = st.executeQuery(sql)) { - while (rs.next()) { - players.add(buildAuthFromResultSet(rs)); - } - } catch (SQLException e) { - logSqlException(e); - } - return players; - } - - - @Override - public boolean setTotpKey(String user, String totpKey) { - String sql = "UPDATE " + tableName + " SET " + col.TOTP_KEY + " = ? WHERE " + col.NAME + " = ?"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, totpKey); - pst.setString(2, user.toLowerCase(Locale.ROOT)); - pst.executeUpdate(); - return true; - } catch (SQLException e) { - logSqlException(e); - } - return false; - } - - private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { - String salt = !col.SALT.isEmpty() ? row.getString(col.SALT) : null; - - return PlayerAuth.builder() - .name(row.getString(col.NAME)) - .email(row.getString(col.EMAIL)) - .realName(row.getString(col.REAL_NAME)) - .password(row.getString(col.PASSWORD), salt) - .totpKey(row.getString(col.TOTP_KEY)) - .lastLogin(getNullableLong(row, col.LAST_LOGIN)) - .lastIp(row.getString(col.LAST_IP)) - .registrationDate(row.getLong(col.REGISTRATION_DATE)) - .registrationIp(row.getString(col.REGISTRATION_IP)) - .locX(row.getDouble(col.LASTLOC_X)) - .locY(row.getDouble(col.LASTLOC_Y)) - .locZ(row.getDouble(col.LASTLOC_Z)) - .locWorld(row.getString(col.LASTLOC_WORLD)) - .locYaw(row.getFloat(col.LASTLOC_YAW)) - .locPitch(row.getFloat(col.LASTLOC_PITCH)) - .build(); - } - - /** - * Creates the column for registration date and sets all entries to the current timestamp. - * We do so in order to avoid issues with purging, where entries with 0 / NULL might get - * purged immediately on startup otherwise. - * - * @param st Statement object to the database - */ - private void addRegistrationDateColumn(Statement st) throws SQLException { - st.executeUpdate("ALTER TABLE " + tableName - + " ADD COLUMN " + col.REGISTRATION_DATE + " TIMESTAMP NOT NULL DEFAULT '0';"); - - // Use the timestamp from Java to avoid timezone issues in case JVM and database are out of sync - long currentTimestamp = System.currentTimeMillis(); - int updatedRows = st.executeUpdate(String.format("UPDATE %s SET %s = %d;", - tableName, col.REGISTRATION_DATE, currentTimestamp)); - logger.info("Created column '" + col.REGISTRATION_DATE + "' and set the current timestamp, " - + currentTimestamp + ", to all " + updatedRows + " rows"); - } - - @Override - String getJdbcUrl(String dataPath, String ignored, String database) { - return "jdbc:sqlite:" + dataPath + File.separator + database + ".db"; - } - - private static void close(Connection con) { - if (con != null) { - try { - con.close(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/SqLiteMigrater.java b/src/main/java/fr/xephi/authme/datasource/SqLiteMigrater.java deleted file mode 100644 index b4a2a577..00000000 --- a/src/main/java/fr/xephi/authme/datasource/SqLiteMigrater.java +++ /dev/null @@ -1,147 +0,0 @@ -package fr.xephi.authme.datasource; - -import com.google.common.io.Files; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * Migrates the SQLite database when necessary. - */ -class SqLiteMigrater { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(SqLiteMigrater.class); - private final File dataFolder; - private final String databaseName; - private final String tableName; - private final Columns col; - - SqLiteMigrater(Settings settings, File dataFolder) { - this.dataFolder = dataFolder; - this.databaseName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - this.col = new Columns(settings); - } - - /** - * Returns whether the database needs to be migrated. - *

- * Background: Before commit 22911a0 (July 2016), new SQLite databases initialized the last IP column to be NOT NULL - * without a default value. Allowing the last IP to be null (#792) is therefore not compatible. - * - * @param metaData the database meta data - * @param tableName the table name (SQLite file name) - * @param col column names configuration - * @return true if a migration is necessary, false otherwise - */ - static boolean isMigrationRequired(DatabaseMetaData metaData, String tableName, Columns col) throws SQLException { - return SqlDataSourceUtils.isNotNullColumn(metaData, tableName, col.LAST_IP) - && SqlDataSourceUtils.getColumnDefaultValue(metaData, tableName, col.LAST_IP) == null; - } - - /** - * Migrates the given SQLite instance. - * - * @param sqLite the instance to migrate - */ - void performMigration(SQLite sqLite) throws SQLException { - logger.warning("YOUR SQLITE DATABASE NEEDS MIGRATING! DO NOT TURN OFF YOUR SERVER"); - - String backupName = createBackup(); - logger.info("Made a backup of your database at 'backups/" + backupName + "'"); - - recreateDatabaseWithNewDefinitions(sqLite); - logger.info("SQLite database migrated successfully"); - } - - private String createBackup() { - File sqLite = new File(dataFolder, databaseName + ".db"); - File backupDirectory = new File(dataFolder, "backups"); - FileUtils.createDirectory(backupDirectory); - - String backupName = "backup-" + databaseName + FileUtils.createCurrentTimeString() + ".db"; - File backup = new File(backupDirectory, backupName); - try { - Files.copy(sqLite, backup); - return backupName; - } catch (IOException e) { - throw new IllegalStateException("Failed to create SQLite backup before migration", e); - } - } - - /** - * Renames the current database, creates a new database under the name and copies the data - * from the renamed database to the newly created one. This is necessary because SQLite - * does not support dropping or modifying a column. - * - * @param sqLite the SQLite instance to migrate - */ - // cf. https://stackoverflow.com/questions/805363/how-do-i-rename-a-column-in-a-sqlite-database-table - private void recreateDatabaseWithNewDefinitions(SQLite sqLite) throws SQLException { - Connection connection = getConnection(sqLite); - String tempTable = "tmp_" + tableName; - try (Statement st = connection.createStatement()) { - st.execute("ALTER TABLE " + tableName + " RENAME TO " + tempTable + ";"); - } - - sqLite.reload(); - connection = getConnection(sqLite); - - try (Statement st = connection.createStatement()) { - String copySql = "INSERT INTO $table ($id, $name, $realName, $password, $lastIp, $lastLogin, $regIp, " - + "$regDate, $locX, $locY, $locZ, $locWorld, $locPitch, $locYaw, $email, $isLogged)" - + "SELECT $id, $name, $realName," - + " $password, CASE WHEN $lastIp = '127.0.0.1' OR $lastIp = '' THEN NULL else $lastIp END," - + " $lastLogin, $regIp, $regDate, $locX, $locY, $locZ, $locWorld, $locPitch, $locYaw," - + " CASE WHEN $email = 'your@email.com' THEN NULL ELSE $email END, $isLogged" - + " FROM " + tempTable + ";"; - int insertedEntries = st.executeUpdate(replaceColumnVariables(copySql)); - logger.info("Copied over " + insertedEntries + " from the old table to the new one"); - - st.execute("DROP TABLE " + tempTable + ";"); - } - } - - private String replaceColumnVariables(String sql) { - String replacedSql = sql.replace("$table", tableName).replace("$id", col.ID) - .replace("$name", col.NAME).replace("$realName", col.REAL_NAME) - .replace("$password", col.PASSWORD).replace("$lastIp", col.LAST_IP) - .replace("$lastLogin", col.LAST_LOGIN).replace("$regIp", col.REGISTRATION_IP) - .replace("$regDate", col.REGISTRATION_DATE).replace("$locX", col.LASTLOC_X) - .replace("$locY", col.LASTLOC_Y).replace("$locZ", col.LASTLOC_Z) - .replace("$locWorld", col.LASTLOC_WORLD).replace("$locPitch", col.LASTLOC_PITCH) - .replace("$locYaw", col.LASTLOC_YAW).replace("$email", col.EMAIL) - .replace("$isLogged", col.IS_LOGGED); - if (replacedSql.contains("$")) { - throw new IllegalStateException("SQL still statement still has '$' in it - was a tag not replaced?" - + " Replacement result: " + replacedSql); - } - return replacedSql; - } - - /** - * Returns the connection from the given SQLite instance. - * - * @param sqLite the SQLite instance to process - * @return the connection to the SQLite database - */ - private static Connection getConnection(SQLite sqLite) { - try { - Field connectionField = SQLite.class.getDeclaredField("con"); - connectionField.setAccessible(true); - return (Connection) connectionField.get(sqLite); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new IllegalStateException("Failed to get the connection from SQLite", e); - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/SqlDataSourceUtils.java b/src/main/java/fr/xephi/authme/datasource/SqlDataSourceUtils.java deleted file mode 100644 index 1a936f02..00000000 --- a/src/main/java/fr/xephi/authme/datasource/SqlDataSourceUtils.java +++ /dev/null @@ -1,109 +0,0 @@ -package fr.xephi.authme.datasource; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * Utilities for SQL data sources. - */ -public final class SqlDataSourceUtils { - - private static final ConsoleLogger logger = ConsoleLoggerFactory.get(SqlDataSourceUtils.class); - - private SqlDataSourceUtils() { - } - - /** - * Logs a SQL exception. - * - * @param e the exception to log - */ - public static void logSqlException(SQLException e) { - logger.logException("Error during SQL operation:", e); - } - - /** - * Returns the long value of a column, or null when appropriate. This method is necessary because - * JDBC's {@link ResultSet#getLong} returns {@code 0} if the entry in the database is {@code null}. - * - * @param rs the result set to read from - * @param columnName the name of the column to retrieve - * @return the value (which may be null) - * @throws SQLException :) - */ - public static Long getNullableLong(ResultSet rs, String columnName) throws SQLException { - long longValue = rs.getLong(columnName); - return rs.wasNull() ? null : longValue; - } - - /** - * Returns whether the given column has a NOT NULL constraint. - * - * @param metaData the database meta data - * @param tableName the name of the table in which the column is - * @param columnName the name of the column to check - * @return true if the column is NOT NULL, false otherwise - * @throws SQLException :) - */ - public static boolean isNotNullColumn(DatabaseMetaData metaData, String tableName, - String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { - if (!rs.next()) { - throw new IllegalStateException("Did not find meta data for column '" - + columnName + "' while checking for not-null constraint"); - } - - int nullableCode = rs.getInt("NULLABLE"); - if (nullableCode == DatabaseMetaData.columnNoNulls) { - return true; - } else if (nullableCode == DatabaseMetaData.columnNullableUnknown) { - logger.warning("Unknown nullable status for column '" + columnName + "'"); - } - } - return false; - } - - /** - * Returns the default value of a column (as per its SQL definition). - * - * @param metaData the database meta data - * @param tableName the name of the table in which the column is - * @param columnName the name of the column to check - * @return the default value of the column (may be null) - * @throws SQLException :) - */ - public static Object getColumnDefaultValue(DatabaseMetaData metaData, String tableName, - String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { - if (!rs.next()) { - throw new IllegalStateException("Did not find meta data for column '" - + columnName + "' while checking its default value"); - } - return rs.getObject("COLUMN_DEF"); - } - } - - /** - * Returns the size of a column (as per its SQL definition). - * - * @param metaData the database meta data - * @param tableName the name of the table in which the column is - * @param columnName the name of the column to check - * @return the size of the column - * @throws SQLException :) - */ - public static int getColumnSize(DatabaseMetaData metaData, String tableName, - String columnName) throws SQLException { - try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) { - if (!rs.next()) { - throw new IllegalStateException("Did not find meta data for column '" - + columnName + "' while checking its size"); - } - return rs.getInt("COLUMN_SIZE"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java deleted file mode 100644 index 47851a5a..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java +++ /dev/null @@ -1,86 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.ColumnOptions.DEFAULT_FOR_NULL; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.ColumnOptions.OPTIONAL; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createDouble; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createFloat; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createInteger; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createLong; -import static fr.xephi.authme.datasource.columnshandler.AuthMeColumnsFactory.createString; - -/** - * Contains column definitions for the AuthMe table. - */ -public final class AuthMeColumns { - - public static final PlayerAuthColumn NAME = createString( - DatabaseSettings.MYSQL_COL_NAME, PlayerAuth::getNickname); - - public static final PlayerAuthColumn NICK_NAME = createString( - DatabaseSettings.MYSQL_COL_REALNAME, PlayerAuth::getRealName); - - public static final PlayerAuthColumn PASSWORD = createString( - DatabaseSettings.MYSQL_COL_PASSWORD, auth -> auth.getPassword().getHash()); - - public static final PlayerAuthColumn SALT = createString( - DatabaseSettings.MYSQL_COL_SALT, auth -> auth.getPassword().getSalt(), OPTIONAL); - - public static final PlayerAuthColumn EMAIL = createString( - DatabaseSettings.MYSQL_COL_EMAIL, PlayerAuth::getEmail, DEFAULT_FOR_NULL); - - public static final PlayerAuthColumn LAST_IP = createString( - DatabaseSettings.MYSQL_COL_LAST_IP, PlayerAuth::getLastIp); - - public static final PlayerAuthColumn GROUP_ID = createInteger( - DatabaseSettings.MYSQL_COL_GROUP, PlayerAuth::getGroupId, OPTIONAL); - - public static final PlayerAuthColumn LAST_LOGIN = createLong( - DatabaseSettings.MYSQL_COL_LASTLOGIN, PlayerAuth::getLastLogin); - - public static final PlayerAuthColumn REGISTRATION_IP = createString( - DatabaseSettings.MYSQL_COL_REGISTER_IP, PlayerAuth::getRegistrationIp); - - public static final PlayerAuthColumn REGISTRATION_DATE = createLong( - DatabaseSettings.MYSQL_COL_REGISTER_DATE, PlayerAuth::getRegistrationDate); - - public static final PlayerAuthColumn UUID = createString( - DatabaseSettings.MYSQL_COL_PLAYER_UUID, - auth -> ( auth.getUuid() == null ? null : auth.getUuid().toString()), - OPTIONAL); - - // -------- - // Location columns - // -------- - public static final PlayerAuthColumn LOCATION_X = createDouble( - DatabaseSettings.MYSQL_COL_LASTLOC_X, PlayerAuth::getQuitLocX); - - public static final PlayerAuthColumn LOCATION_Y = createDouble( - DatabaseSettings.MYSQL_COL_LASTLOC_Y, PlayerAuth::getQuitLocY); - - public static final PlayerAuthColumn LOCATION_Z = createDouble( - DatabaseSettings.MYSQL_COL_LASTLOC_Z, PlayerAuth::getQuitLocZ); - - public static final PlayerAuthColumn LOCATION_WORLD = createString( - DatabaseSettings.MYSQL_COL_LASTLOC_WORLD, PlayerAuth::getWorld); - - public static final PlayerAuthColumn LOCATION_YAW = createFloat( - DatabaseSettings.MYSQL_COL_LASTLOC_YAW, PlayerAuth::getYaw); - - public static final PlayerAuthColumn LOCATION_PITCH = createFloat( - DatabaseSettings.MYSQL_COL_LASTLOC_PITCH, PlayerAuth::getPitch); - - // -------- - // Columns not on PlayerAuth - // -------- - public static final DataSourceColumn IS_LOGGED = createInteger( - DatabaseSettings.MYSQL_COL_ISLOGGED); - - public static final DataSourceColumn HAS_SESSION = createInteger( - DatabaseSettings.MYSQL_COL_HASSESSION); - - private AuthMeColumns() { - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java deleted file mode 100644 index 3400f76c..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import ch.jalu.configme.properties.Property; -import ch.jalu.datasourcecolumns.ColumnType; -import ch.jalu.datasourcecolumns.StandardTypes; -import fr.xephi.authme.data.auth.PlayerAuth; - -import java.util.function.Function; - -/** - * Util class for initializing {@link DataSourceColumn} objects. - */ -final class AuthMeColumnsFactory { - - private AuthMeColumnsFactory() { - } - - static DataSourceColumn createInteger(Property nameProperty, - ColumnOptions... options) { - return new DataSourceColumn<>(StandardTypes.INTEGER, nameProperty, - isOptional(options), hasDefaultForNull(options)); - } - - static PlayerAuthColumn createInteger(Property nameProperty, - Function playerAuthGetter, - ColumnOptions... options) { - return createInternal(StandardTypes.INTEGER, nameProperty, playerAuthGetter, options); - } - - static PlayerAuthColumn createLong(Property nameProperty, - Function playerAuthGetter, - ColumnOptions... options) { - return createInternal(StandardTypes.LONG, nameProperty, playerAuthGetter, options); - } - - static PlayerAuthColumn createString(Property nameProperty, - Function playerAuthGetter, - ColumnOptions... options) { - return createInternal(StandardTypes.STRING, nameProperty, playerAuthGetter, options); - } - - static PlayerAuthColumn createDouble(Property nameProperty, - Function playerAuthGetter, - ColumnOptions... options) { - return createInternal(StandardTypes.DOUBLE, nameProperty, playerAuthGetter, options); - } - - static PlayerAuthColumn createFloat(Property nameProperty, - Function playerAuthGetter, - ColumnOptions... options) { - return createInternal(StandardTypes.FLOAT, nameProperty, playerAuthGetter, options); - } - - private static PlayerAuthColumn createInternal(ColumnType type, Property nameProperty, - Function authGetter, - ColumnOptions... options) { - return new PlayerAuthColumn<>(type, nameProperty, isOptional(options), hasDefaultForNull(options), authGetter); - } - - private static boolean isOptional(ColumnOptions[] options) { - return containsInArray(ColumnOptions.OPTIONAL, options); - } - - private static boolean hasDefaultForNull(ColumnOptions[] options) { - return containsInArray(ColumnOptions.DEFAULT_FOR_NULL, options); - } - - private static boolean containsInArray(ColumnOptions needle, ColumnOptions[] haystack) { - for (ColumnOptions option : haystack) { - if (option == needle) { - return true; - } - } - return false; - } - - enum ColumnOptions { - - OPTIONAL, - - DEFAULT_FOR_NULL - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java deleted file mode 100644 index b910d36e..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java +++ /dev/null @@ -1,227 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import ch.jalu.datasourcecolumns.data.DataSourceValue; -import ch.jalu.datasourcecolumns.data.DataSourceValues; -import ch.jalu.datasourcecolumns.data.UpdateValues; -import ch.jalu.datasourcecolumns.predicate.Predicate; -import ch.jalu.datasourcecolumns.sqlimplementation.PredicateSqlGenerator; -import ch.jalu.datasourcecolumns.sqlimplementation.SqlColumnsHandler; -import ch.jalu.datasourcecolumns.sqlimplementation.statementgenerator.ConnectionSupplier; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; -import java.util.Locale; - -import static ch.jalu.datasourcecolumns.sqlimplementation.SqlColumnsHandlerConfig.forConnectionPool; -import static ch.jalu.datasourcecolumns.sqlimplementation.SqlColumnsHandlerConfig.forSingleConnection; -import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; - -/** - * Wrapper of {@link SqlColumnsHandler} for the AuthMe data table. - * Wraps exceptions and provides better support for operations based on a {@link PlayerAuth} object. - */ -public final class AuthMeColumnsHandler { - - private final SqlColumnsHandler internalHandler; - - private AuthMeColumnsHandler(SqlColumnsHandler internalHandler) { - this.internalHandler = internalHandler; - } - - /** - * Creates a column handler for SQLite. - * - * @param connection the connection to the database - * @param settings plugin settings - * @return created column handler - */ - public static AuthMeColumnsHandler createForSqlite(Connection connection, Settings settings) { - ColumnContext columnContext = new ColumnContext(settings, false); - String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); - - SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( - forSingleConnection(connection, tableName, nameColumn, columnContext) - .setPredicateSqlGenerator(new PredicateSqlGenerator<>(columnContext, true)) - ); - return new AuthMeColumnsHandler(sqlColHandler); - } - - /** - * Creates a column handler for H2. - * - * @param connection the connection to the database - * @param settings plugin settings - * @return created column handler - */ - public static AuthMeColumnsHandler createForH2(Connection connection, Settings settings) { - ColumnContext columnContext = new ColumnContext(settings, false); - String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); - - SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( - forSingleConnection(connection, tableName, nameColumn, columnContext) - .setPredicateSqlGenerator(new PredicateSqlGenerator<>(columnContext, false)) - ); - return new AuthMeColumnsHandler(sqlColHandler); - } - - - /** - * Creates a column handler for MySQL. - * - * @param connectionSupplier supplier of connections from the connection pool - * @param settings plugin settings - * @return created column handler - */ - public static AuthMeColumnsHandler createForMySql(ConnectionSupplier connectionSupplier, Settings settings) { - ColumnContext columnContext = new ColumnContext(settings, true); - String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); - - SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( - forConnectionPool(connectionSupplier, tableName, nameColumn, columnContext)); - return new AuthMeColumnsHandler(sqlColHandler); - } - - /** - * Changes a column from a specific row to the given value. - * - * @param name name of the account to modify - * @param column the column to modify - * @param value the value to set the column to - * @param the column type - * @return true upon success, false otherwise - */ - public boolean update(String name, DataSourceColumn column, T value) { - try { - return internalHandler.update(name.toLowerCase(Locale.ROOT), column, value); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - /** - * Updates a row to have the values as retrieved from the PlayerAuth object. - * - * @param auth the player auth object to modify and to get values from - * @param columns the columns to update in the row - * @return true upon success, false otherwise - */ - public boolean update(PlayerAuth auth, PlayerAuthColumn... columns) { - try { - return internalHandler.update(auth.getNickname(), auth, columns); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - /** - * Updates a row to have the given values. - * - * @param name the name of the account to modify - * @param updateValues the values to set on the row - * @return true upon success, false otherwise - */ - public boolean update(String name, UpdateValues updateValues) { - try { - return internalHandler.update(name.toLowerCase(Locale.ROOT), updateValues); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - /** - * Sets the given value to the provided column for all rows which match the predicate. - * - * @param predicate the predicate to filter rows by - * @param column the column to modify on the matched rows - * @param value the new value to set - * @param the column type - * @return number of modified rows - */ - public int update(Predicate predicate, DataSourceColumn column, T value) { - try { - return internalHandler.update(predicate, column, value); - } catch (SQLException e) { - logSqlException(e); - return 0; - } - } - - /** - * Retrieves the given column from a given row. - * - * @param name the account name to look up - * @param column the column whose value should be retrieved - * @param the column type - * @return the result of the lookup - * @throws SQLException . - */ - public DataSourceValue retrieve(String name, DataSourceColumn column) throws SQLException { - return internalHandler.retrieve(name.toLowerCase(Locale.ROOT), column); - } - - /** - * Retrieves multiple values from a given row. - * - * @param name the account name to look up - * @param columns the columns to retrieve - * @return map-like object with the requested values - * @throws SQLException . - */ - public DataSourceValues retrieve(String name, DataSourceColumn... columns) throws SQLException { - return internalHandler.retrieve(name.toLowerCase(Locale.ROOT), columns); - } - - /** - * Retrieves a column's value for all rows that satisfy the given predicate. - * - * @param predicate the predicate to fulfill - * @param column the column to retrieve from the matching rows - * @param the column's value type - * @return the values of the matching rows - * @throws SQLException . - */ - public List retrieve(Predicate predicate, DataSourceColumn column) throws SQLException { - return internalHandler.retrieve(predicate, column); - } - - /** - * Inserts the given values into a new row, as taken from the player auth. - * - * @param auth the player auth to get values from - * @param columns the columns to insert - * @return true upon success, false otherwise - */ - public boolean insert(PlayerAuth auth, PlayerAuthColumn... columns) { - try { - return internalHandler.insert(auth, columns); - } catch (SQLException e) { - logSqlException(e); - return false; - } - } - - /** - * Returns the number of rows that match the provided predicate. - * - * @param predicate the predicate to test the rows for - * @return number of rows fulfilling the predicate - */ - public int count(Predicate predicate) { - try { - return internalHandler.count(predicate); - } catch (SQLException e) { - logSqlException(e); - return 0; - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java deleted file mode 100644 index 483e31e9..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/ColumnContext.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import fr.xephi.authme.settings.Settings; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Context for resolving the properties of {@link AuthMeColumns} entries. - */ -public class ColumnContext { - - private final Settings settings; - private final Map, String> columnNames = new ConcurrentHashMap<>(); - private final boolean hasDefaultSupport; - - /** - * Constructor. - * - * @param settings plugin settings - * @param hasDefaultSupport whether or not the underlying database has support for the {@code DEFAULT} keyword - */ - public ColumnContext(Settings settings, boolean hasDefaultSupport) { - this.settings = settings; - this.hasDefaultSupport = hasDefaultSupport; - } - - public String getName(DataSourceColumn column) { - return columnNames.computeIfAbsent(column, k -> settings.getProperty(k.getNameProperty())); - } - - public boolean hasDefaultSupport() { - return hasDefaultSupport; - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java deleted file mode 100644 index 4b7fa4ca..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/DataSourceColumn.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import ch.jalu.configme.properties.Property; -import ch.jalu.datasourcecolumns.Column; -import ch.jalu.datasourcecolumns.ColumnType; - -/** - * Basic {@link Column} implementation for AuthMe. - * - * @param column type - */ -public class DataSourceColumn implements Column { - - private final ColumnType columnType; - private final Property nameProperty; - private final boolean isOptional; - private final boolean useDefaultForNull; - - /** - * Constructor. - * - * @param type type of the column - * @param nameProperty property defining the column name - * @param isOptional whether or not the column can be skipped (if name is configured to empty string) - * @param useDefaultForNull whether SQL DEFAULT should be used for null values (if supported by the database) - */ - DataSourceColumn(ColumnType type, Property nameProperty, boolean isOptional, boolean useDefaultForNull) { - this.columnType = type; - this.nameProperty = nameProperty; - this.isOptional = isOptional; - this.useDefaultForNull = useDefaultForNull; - } - - public Property getNameProperty() { - return nameProperty; - } - - @Override - public String resolveName(ColumnContext columnContext) { - return columnContext.getName(this); - } - - @Override - public ColumnType getType() { - return columnType; - } - - @Override - public boolean isColumnUsed(ColumnContext columnContext) { - return !isOptional || !resolveName(columnContext).isEmpty(); - } - - @Override - public boolean useDefaultForNullValue(ColumnContext columnContext) { - return useDefaultForNull && columnContext.hasDefaultSupport(); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java deleted file mode 100644 index 43d022b1..00000000 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/PlayerAuthColumn.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.xephi.authme.datasource.columnshandler; - -import ch.jalu.configme.properties.Property; -import ch.jalu.datasourcecolumns.ColumnType; -import ch.jalu.datasourcecolumns.DependentColumn; -import fr.xephi.authme.data.auth.PlayerAuth; - -import java.util.function.Function; - -/** - * Implementation for columns which can also be retrieved from a {@link PlayerAuth} object. - * - * @param column type - */ -public class PlayerAuthColumn extends DataSourceColumn implements DependentColumn { - - private final Function playerAuthGetter; - - /* - * Constructor. See parent class for details. - */ - PlayerAuthColumn(ColumnType type, Property nameProperty, boolean isOptional, boolean useDefaultForNull, - Function playerAuthGetter) { - super(type, nameProperty, isOptional, useDefaultForNull); - this.playerAuthGetter = playerAuthGetter; - } - - @Override - public T getValueFromDependent(PlayerAuth auth) { - return playerAuthGetter.apply(auth); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/AbstractDataSourceConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/AbstractDataSourceConverter.java deleted file mode 100644 index fdced2fa..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/AbstractDataSourceConverter.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.List; - -import static fr.xephi.authme.util.Utils.logAndSendMessage; - -/** - * Converts from one AuthMe data source type to another. - * - * @param the source type to convert from - */ -public abstract class AbstractDataSourceConverter implements Converter { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(MySqlToSqlite.class); - - private final DataSource destination; - private final DataSourceType destinationType; - - /** - * Constructor. - * - * @param destination the data source to convert to - * @param destinationType the data source type of the destination. The given data source is checked that its - * type corresponds to this type before the conversion is started, enabling us to just pass - * the current data source and letting this class check that the types correspond. - */ - public AbstractDataSourceConverter(DataSource destination, DataSourceType destinationType) { - this.destination = destination; - this.destinationType = destinationType; - } - - // Implementation note: Because of ForceFlatToSqlite it is possible that the CommandSender is null, - // which is never the case when a converter is launched from the /authme converter command. - @Override - public void execute(CommandSender sender) { - if (destinationType != destination.getType()) { - if (sender != null) { - sender.sendMessage("Please configure your connection to " - + destinationType + " and re-run this command"); - } - return; - } - - S source; - try { - source = getSource(); - } catch (Exception e) { - logAndSendMessage(sender, "The data source to convert from could not be initialized"); - logger.logException("Could not initialize source:", e); - return; - } - - List skippedPlayers = new ArrayList<>(); - for (PlayerAuth auth : source.getAllAuths()) { - if (destination.isAuthAvailable(auth.getNickname())) { - skippedPlayers.add(auth.getNickname()); - } else { - destination.saveAuth(auth); - destination.updateSession(auth); - destination.updateQuitLoc(auth); - } - } - - if (!skippedPlayers.isEmpty()) { - logAndSendMessage(sender, "Skipped conversion for players which were already in " - + destinationType + ": " + String.join(", ", skippedPlayers)); - } - logAndSendMessage(sender, "Database successfully converted from " + source.getType() - + " to " + destinationType); - } - - /** - * @return the data source to convert from - * @throws Exception during initialization of source - */ - protected abstract S getSource() throws Exception; -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/Converter.java b/src/main/java/fr/xephi/authme/datasource/converter/Converter.java deleted file mode 100644 index 7549bb48..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/Converter.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import org.bukkit.command.CommandSender; - -/** - * Interface for AuthMe converters. - */ -public interface Converter { - - /** - * Execute the conversion. - * - * @param sender the sender who initialized the conversion - */ - void execute(CommandSender sender); -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java deleted file mode 100644 index a9197223..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java +++ /dev/null @@ -1,82 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.ConverterSettings; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.Locale; - -/** - * Converter for CrazyLogin to AuthMe. - */ -public class CrazyLoginConverter implements Converter { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(CrazyLoginConverter.class); - - private final DataSource database; - private final Settings settings; - private final File dataFolder; - - @Inject - CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings) { - this.dataFolder = dataFolder; - this.database = dataSource; - this.settings = settings; - } - - @Override - public void execute(CommandSender sender) { - String fileName = settings.getProperty(ConverterSettings.CRAZYLOGIN_FILE_NAME); - File source = new File(dataFolder, fileName); - if (!source.exists()) { - sender.sendMessage("CrazyLogin file not found, please put " + fileName + " in AuthMe folder!"); - return; - } - - String line; - try (BufferedReader users = new BufferedReader(new FileReader(source))) { - while ((line = users.readLine()) != null) { - if (line.contains("|")) { - migrateAccount(line); - } - } - logger.info("CrazyLogin database has been imported correctly"); - } catch (IOException ex) { - logger.warning("Can't open the crazylogin database file! Does it exist?"); - logger.logException("Encountered", ex); - } - } - - /** - * Moves an account from CrazyLogin to the AuthMe database. - * - * @param line line read from the CrazyLogin file (one account) - */ - private void migrateAccount(String line) { - String[] args = line.split("\\|"); - if (args.length < 2 || "name".equalsIgnoreCase(args[0])) { - return; - } - String playerName = args[0]; - String password = args[1]; - if (password != null) { - PlayerAuth auth = PlayerAuth.builder() - .name(playerName.toLowerCase(Locale.ROOT)) - .realName(playerName) - .password(password, null) - .build(); - database.saveAuth(auth); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/H2ToSqlite.java b/src/main/java/fr/xephi/authme/datasource/converter/H2ToSqlite.java deleted file mode 100644 index 03520b80..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/H2ToSqlite.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.datasource.H2; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.settings.Settings; - -import javax.inject.Inject; -import java.io.File; -import java.sql.SQLException; - -/** - * Converts H2 to SQLite. - * - */ -public class H2ToSqlite extends AbstractDataSourceConverter

{ - - private final Settings settings; - private final File dataFolder; - - @Inject - H2ToSqlite(Settings settings, DataSource dataSource, @DataFolder File dataFolder) { - super(dataSource, DataSourceType.SQLITE); - this.settings = settings; - this.dataFolder = dataFolder; - } - - @Override - protected H2 getSource() throws SQLException { - return new H2(settings, dataFolder); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/LoginSecurityConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/LoginSecurityConverter.java deleted file mode 100644 index dbdce5df..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/LoginSecurityConverter.java +++ /dev/null @@ -1,210 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.ConverterSettings; -import fr.xephi.authme.util.UuidUtils; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static fr.xephi.authme.util.Utils.logAndSendMessage; - -/** - * Converts data from LoginSecurity to AuthMe. - */ -public class LoginSecurityConverter implements Converter { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(LoginSecurityConverter.class); - private final File dataFolder; - private final DataSource dataSource; - - private final boolean useSqlite; - private final String mySqlHost; - private final String mySqlDatabase; - private final String mySqlUser; - private final String mySqlPassword; - - @Inject - LoginSecurityConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings) { - this.dataFolder = dataFolder; - this.dataSource = dataSource; - - useSqlite = settings.getProperty(ConverterSettings.LOGINSECURITY_USE_SQLITE); - mySqlHost = settings.getProperty(ConverterSettings.LOGINSECURITY_MYSQL_HOST); - mySqlDatabase = settings.getProperty(ConverterSettings.LOGINSECURITY_MYSQL_DATABASE); - mySqlUser = settings.getProperty(ConverterSettings.LOGINSECURITY_MYSQL_USER); - mySqlPassword = settings.getProperty(ConverterSettings.LOGINSECURITY_MYSQL_PASSWORD); - } - - @Override - public void execute(CommandSender sender) { - try (Connection connection = createConnectionOrInformSender(sender)) { - if (connection != null) { - performConversion(sender, connection); - logger.info("LoginSecurity conversion completed! Please remember to set \"legacyHashes: ['BCRYPT']\" " - + "in your configuration file!"); - } - } catch (SQLException e) { - sender.sendMessage("Failed to convert from SQLite. Please see the log for more info"); - logger.logException("Could not fetch or migrate data:", e); - } - } - - /** - * Performs the conversion from LoginSecurity to AuthMe. - * - * @param sender the command sender who launched the conversion - * @param connection connection to the LoginSecurity data source - */ - @VisibleForTesting - void performConversion(CommandSender sender, Connection connection) throws SQLException { - try (Statement statement = connection.createStatement()) { - statement.execute( - "SELECT * from ls_players LEFT JOIN ls_locations ON ls_locations.id = ls_players.id"); - try (ResultSet resultSet = statement.getResultSet()) { - migrateData(sender, resultSet); - } - } - } - - /** - * Migrates the accounts. - * - * @param sender the command sender - * @param resultSet result set with the account data to migrate - */ - private void migrateData(CommandSender sender, ResultSet resultSet) throws SQLException { - List skippedPlayers = new ArrayList<>(); - long successfulSaves = 0; - while (resultSet.next()) { - String name = resultSet.getString("last_name"); - if (dataSource.isAuthAvailable(name)) { - skippedPlayers.add(name); - } else { - PlayerAuth auth = buildAuthFromLoginSecurity(name, resultSet); - dataSource.saveAuth(auth); - dataSource.updateSession(auth); - ++successfulSaves; - } - } - - logAndSendMessage(sender, "Migrated " + successfulSaves + " accounts successfully from LoginSecurity"); - if (!skippedPlayers.isEmpty()) { - logAndSendMessage(sender, "Skipped conversion for players which were already in AuthMe: " - + String.join(", ", skippedPlayers)); - } - } - - /** - * Creates a PlayerAuth based on data extracted from the given result set. - * - * @param name the name of the player to build - * @param resultSet the result set to extract data from - * @return the created player auth object - */ - private static PlayerAuth buildAuthFromLoginSecurity(String name, ResultSet resultSet) throws SQLException { - Long lastLoginMillis = Optional.ofNullable(resultSet.getTimestamp("last_login")) - .map(Timestamp::getTime).orElse(null); - long regDate = Optional.ofNullable(resultSet.getDate("registration_date")) - .map(Date::getTime).orElse(System.currentTimeMillis()); - UUID uuid = UuidUtils.parseUuidSafely(resultSet.getString("unique_user_id")); - return PlayerAuth.builder() - .name(name) - .realName(name) - .password(resultSet.getString("password"), null) - .lastIp(resultSet.getString("ip_address")) - .lastLogin(lastLoginMillis) - .registrationDate(regDate) - .locX(resultSet.getDouble("x")) - .locY(resultSet.getDouble("y")) - .locZ(resultSet.getDouble("z")) - .locWorld(resultSet.getString("world")) - .locYaw(resultSet.getFloat("yaw")) - .locPitch(resultSet.getFloat("pitch")) - .uuid(uuid) - .build(); - } - - /** - * Creates a {@link Connection} to the LoginSecurity data source based on the settings, - * or informs the sender of the error that occurred. - * - * @param sender the command sender who launched the conversion - * @return the created connection object, or null if it failed - */ - private Connection createConnectionOrInformSender(CommandSender sender) { - Connection connection; - if (useSqlite) { - File sqliteDatabase = new File(dataFolder.getParentFile(), "LoginSecurity/LoginSecurity.db"); - if (!sqliteDatabase.exists()) { - sender.sendMessage("The file '" + sqliteDatabase.getPath() + "' does not exist"); - return null; - } - connection = createSqliteConnection("plugins/LoginSecurity/LoginSecurity.db"); - } else { - if (mySqlDatabase.isEmpty() || mySqlUser.isEmpty()) { - sender.sendMessage("The LoginSecurity database or username is not configured in AuthMe's config.yml"); - return null; - } - connection = createMySqlConnection(); - } - - if (connection == null) { - sender.sendMessage("Could not connect to LoginSecurity using Sqlite = " - + useSqlite + ", see log for more info"); - return null; - } - return connection; - } - - /** - * Creates a connection to SQLite. - * - * @param path the path to the SQLite database - * @return the created connection - */ - @VisibleForTesting - Connection createSqliteConnection(String path) { - try { - Class.forName("org.sqlite.JDBC"); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e); - } - - try { - return DriverManager.getConnection( - "jdbc:sqlite:" + path, "trump", "donald"); - } catch (SQLException e) { - logger.logException("Could not connect to SQLite database", e); - return null; - } - } - - private Connection createMySqlConnection() { - try { - return DriverManager.getConnection( - "jdbc:mysql://" + mySqlHost + "/" + mySqlDatabase, mySqlUser, mySqlPassword); - } catch (SQLException e) { - logger.logException("Could not connect to SQLite database", e); - return null; - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java b/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java deleted file mode 100644 index b1a485b9..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/MySqlToSqlite.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.datasource.MySQL; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.settings.Settings; - -import javax.inject.Inject; -import java.sql.SQLException; - -/** - * Converts from MySQL to SQLite. - */ -public class MySqlToSqlite extends AbstractDataSourceConverter { - - private final Settings settings; - private final MySqlExtensionsFactory mySqlExtensionsFactory; - - @Inject - MySqlToSqlite(DataSource dataSource, Settings settings, MySqlExtensionsFactory mySqlExtensionsFactory) { - super(dataSource, DataSourceType.SQLITE); - this.settings = settings; - this.mySqlExtensionsFactory = mySqlExtensionsFactory; - } - - @Override - protected MySQL getSource() throws SQLException { - return new MySQL(settings, mySqlExtensionsFactory); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/RoyalAuthConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/RoyalAuthConverter.java deleted file mode 100644 index ebb9080e..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/RoyalAuthConverter.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import javax.inject.Inject; -import java.io.File; -import java.util.Locale; - -import static fr.xephi.authme.util.FileUtils.makePath; - -public class RoyalAuthConverter implements Converter { - - private static final String LAST_LOGIN_PATH = "timestamps.quit"; - private static final String PASSWORD_PATH = "login.password"; - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(RoyalAuthConverter.class); - - private final AuthMe plugin; - private final DataSource dataSource; - - @Inject - RoyalAuthConverter(AuthMe plugin, DataSource dataSource) { - this.plugin = plugin; - this.dataSource = dataSource; - } - - @Override - public void execute(CommandSender sender) { - for (OfflinePlayer player : plugin.getServer().getOfflinePlayers()) { - try { - String name = player.getName().toLowerCase(Locale.ROOT); - File file = new File(makePath(".", "plugins", "RoyalAuth", "userdata", name + ".yml")); - - if (dataSource.isAuthAvailable(name) || !file.exists()) { - continue; - } - FileConfiguration configuration = YamlConfiguration.loadConfiguration(file); - PlayerAuth auth = PlayerAuth.builder() - .name(name) - .password(configuration.getString(PASSWORD_PATH), null) - .lastLogin(configuration.getLong(LAST_LOGIN_PATH)) - .realName(player.getName()) - .build(); - - dataSource.saveAuth(auth); - dataSource.updateSession(auth); - } catch (Exception e) { - logger.logException("Error while trying to import " + player.getName() + " RoyalAuth data", e); - } - } - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/SqliteToH2.java b/src/main/java/fr/xephi/authme/datasource/converter/SqliteToH2.java deleted file mode 100644 index eea2bfca..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/SqliteToH2.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.datasource.SQLite; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.settings.Settings; - -import javax.inject.Inject; -import java.io.File; -import java.sql.SQLException; - -/** - * Converts SQLite to H2 - * - */ -public class SqliteToH2 extends AbstractDataSourceConverter{ - - private final Settings settings; - private final File dataFolder; - - @Inject - SqliteToH2(Settings settings, DataSource dataSource, @DataFolder File dataFolder) { - super(dataSource, DataSourceType.H2); - this.settings = settings; - this.dataFolder = dataFolder; - } - - @Override - protected SQLite getSource() throws SQLException { - return new SQLite(settings, dataFolder); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/SqliteToSql.java b/src/main/java/fr/xephi/authme/datasource/converter/SqliteToSql.java deleted file mode 100644 index cc472da2..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/SqliteToSql.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.datasource.SQLite; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.settings.Settings; - -import javax.inject.Inject; -import java.io.File; -import java.sql.SQLException; - -/** - * Converts from SQLite to MySQL. - */ -public class SqliteToSql extends AbstractDataSourceConverter { - - private final Settings settings; - private final File dataFolder; - - @Inject - SqliteToSql(Settings settings, DataSource dataSource, @DataFolder File dataFolder) { - super(dataSource, DataSourceType.MYSQL); - this.settings = settings; - this.dataFolder = dataFolder; - } - - @Override - protected SQLite getSource() throws SQLException { - return new SQLite(settings, dataFolder); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/converter/XAuthConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/XAuthConverter.java deleted file mode 100644 index 0f04310c..00000000 --- a/src/main/java/fr/xephi/authme/datasource/converter/XAuthConverter.java +++ /dev/null @@ -1,149 +0,0 @@ -package fr.xephi.authme.datasource.converter; - -import de.luricos.bukkit.xAuth.database.DatabaseTables; -import de.luricos.bukkit.xAuth.utils.xAuthLog; -import de.luricos.bukkit.xAuth.xAuth; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.util.Utils; -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.PluginManager; - -import javax.inject.Inject; -import java.io.File; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import static fr.xephi.authme.util.FileUtils.makePath; - -public class XAuthConverter implements Converter { - - @Inject - @DataFolder - private File dataFolder; - @Inject - private DataSource database; - @Inject - private PluginManager pluginManager; - - XAuthConverter() { - } - - @Override - public void execute(CommandSender sender) { - try { - Class.forName("de.luricos.bukkit.xAuth.xAuth"); - convert(sender); - } catch (ClassNotFoundException ce) { - sender.sendMessage("xAuth has not been found, please put xAuth.jar in your plugin folder and restart!"); - } - } - - private void convert(CommandSender sender) { - if (pluginManager.getPlugin("xAuth") == null) { - sender.sendMessage("[AuthMe] xAuth plugin not found"); - return; - } - //TODO ljacqu 20160702: xAuthDb is not used except for the existence check -- is this intended? - File xAuthDb = new File(dataFolder.getParent(), makePath("xAuth", "xAuth.h2.db")); - if (!xAuthDb.exists()) { - sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data..."); - } - List players = getXAuthPlayers(); - if (Utils.isCollectionEmpty(players)) { - sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players"); - return; - } - sender.sendMessage("[AuthMe] Starting import..."); - - for (int id : players) { - String pl = getIdPlayer(id); - String psw = getPassword(id); - if (psw != null && !psw.isEmpty() && pl != null) { - PlayerAuth auth = PlayerAuth.builder() - .name(pl.toLowerCase(Locale.ROOT)) - .realName(pl) - .password(psw, null).build(); - database.saveAuth(auth); - } - } - sender.sendMessage("[AuthMe] Successfully converted from xAuth database"); - } - - private String getIdPlayer(int id) { - String realPass = ""; - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - ps.setInt(1, id); - rs = ps.executeQuery(); - if (!rs.next()) { - return null; - } - realPass = rs.getString("playername").toLowerCase(Locale.ROOT); - } catch (SQLException e) { - xAuthLog.severe("Failed to retrieve name for account: " + id, e); - return null; - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return realPass; - } - - private List getXAuthPlayers() { - List xP = new ArrayList<>(); - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT * FROM `%s`", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - rs = ps.executeQuery(); - while (rs.next()) { - xP.add(rs.getInt("id")); - } - } catch (SQLException e) { - xAuthLog.severe("Cannot import xAuthPlayers", e); - return new ArrayList<>(); - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return xP; - } - - private String getPassword(int accountId) { - String realPass = ""; - Connection conn = xAuth.getPlugin().getDatabaseController().getConnection(); - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?", - xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT)); - ps = conn.prepareStatement(sql); - ps.setInt(1, accountId); - rs = ps.executeQuery(); - if (!rs.next()) { - return null; - } - realPass = rs.getString("password"); - } catch (SQLException e) { - xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e); - return null; - } finally { - xAuth.getPlugin().getDatabaseController().close(conn, ps, rs); - } - return realPass; - } - -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java deleted file mode 100644 index 2f39b8f7..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/Ipb4Extension.java +++ /dev/null @@ -1,55 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -/** - * Extension for IPB4. - */ -class Ipb4Extension extends MySqlExtension { - - private final String ipbPrefix; - private final int ipbGroup; - - Ipb4Extension(Settings settings, Columns col) { - super(settings, col); - this.ipbPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX); - this.ipbGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID); - } - - @Override - public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { - // Update player group in core_members - String sql = "UPDATE " + ipbPrefix + tableName - + " SET " + tableName + ".member_group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setInt(1, ipbGroup); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Get current time without ms - long time = System.currentTimeMillis() / 1000; - // update joined date - sql = "UPDATE " + ipbPrefix + tableName - + " SET " + tableName + ".joined=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - // Update last_visit - sql = "UPDATE " + ipbPrefix + tableName - + " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst2 = con.prepareStatement(sql)) { - pst2.setLong(1, time); - pst2.setString(2, auth.getNickname()); - pst2.executeUpdate(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java deleted file mode 100644 index 07374dfb..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtension.java +++ /dev/null @@ -1,96 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.OptionalInt; - -/** - * Extension for the MySQL data source for forums. For certain password hashes (e.g. phpBB), we want - * to hook into the forum board and execute some actions specific to the forum software. - */ -public abstract class MySqlExtension { - - protected final Columns col; - protected final String tableName; - - MySqlExtension(Settings settings, Columns col) { - this.col = col; - this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - } - - /** - * Performs additional actions when a new player is saved. - * - * @param auth the player auth that has been saved - * @param con connection to the sql table - * @throws SQLException . - */ - public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { - // extend for custom behavior - } - - /** - * Writes properties to the given PlayerAuth object that need to be retrieved in a specific manner - * when a PlayerAuth object is read from the table. - * - * @param auth the player auth object to extend - * @param id the database id of the player auth entry - * @param con connection to the sql table - * @throws SQLException . - */ - public void extendAuth(PlayerAuth auth, int id, Connection con) throws SQLException { - // extend for custom behavior - } - - /** - * Performs additional actions when a user's password is changed. - * - * @param user the name of the player (lowercase) - * @param password the new password to set - * @param con connection to the sql table - * @throws SQLException . - */ - public void changePassword(String user, HashedPassword password, Connection con) throws SQLException { - // extend for custom behavior - } - - /** - * Performs additional actions when a player is removed from the database. - * - * @param user the user to remove - * @param con connection to the sql table - * @throws SQLException . - */ - public void removeAuth(String user, Connection con) throws SQLException { - // extend for custom behavior - } - - /** - * Fetches the database ID of the given name from the database. - * - * @param name the name to get the ID for - * @param con connection to the sql table - * @return id of the playerAuth, or empty OptionalInt if the name is not registered - * @throws SQLException . - */ - protected OptionalInt retrieveIdFromTable(String name, Connection con) throws SQLException { - String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, name); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return OptionalInt.of(rs.getInt(col.ID)); - } - } - } - return OptionalInt.empty(); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java deleted file mode 100644 index dda94d78..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/MySqlExtensionsFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; - -import javax.inject.Inject; - -/** - * Creates the appropriate {@link MySqlExtension}, depending on the configured password hashing algorithm. - */ -public class MySqlExtensionsFactory { - - @Inject - private Settings settings; - - /** - * Creates a new {@link MySqlExtension} object according to the configured hash algorithm. - * - * @param columnsConfig the columns configuration - * @return the extension the MySQL data source should use - */ - public MySqlExtension buildExtension(Columns columnsConfig) { - HashAlgorithm hash = settings.getProperty(SecuritySettings.PASSWORD_HASH); - switch (hash) { - case IPB4: - return new Ipb4Extension(settings, columnsConfig); - case PHPBB: - return new PhpBbExtension(settings, columnsConfig); - case WORDPRESS: - return new WordpressExtension(settings, columnsConfig); - case XFBCRYPT: - return new XfBcryptExtension(settings, columnsConfig); - default: - return new NoOpExtension(settings, columnsConfig); - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java deleted file mode 100644 index 6d15f837..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/NoOpExtension.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.settings.Settings; - -/** - * Extension implementation that does not do anything. - */ -class NoOpExtension extends MySqlExtension { - - NoOpExtension(Settings settings, Columns col) { - super(settings, col); - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java deleted file mode 100644 index d78aded1..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/PhpBbExtension.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.OptionalInt; - -/** - * Extensions for phpBB when MySQL is used as data source. - */ -class PhpBbExtension extends MySqlExtension { - - private final String phpBbPrefix; - private final int phpBbGroup; - - PhpBbExtension(Settings settings, Columns col) { - super(settings, col); - this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); - this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); - } - - @Override - public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { - OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con); - if (authId.isPresent()) { - updateSpecificsOnSave(authId.getAsInt(), auth.getNickname(), con); - } - } - - private void updateSpecificsOnSave(int id, String name, Connection con) throws SQLException { - // Insert player in phpbb_user_group - String sql = "INSERT INTO " + phpBbPrefix - + "user_group (group_id, user_id, group_leader, user_pending) VALUES (?,?,?,?);"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, phpBbGroup); - pst.setInt(2, id); - pst.setInt(3, 0); - pst.setInt(4, 0); - pst.executeUpdate(); - } - // Update username_clean in phpbb_users - sql = "UPDATE " + tableName + " SET " + tableName + ".username_clean=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, name); - pst.setString(2, name); - pst.executeUpdate(); - } - // Update player group in phpbb_users - sql = "UPDATE " + tableName + " SET " + tableName + ".group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, phpBbGroup); - pst.setString(2, name); - pst.executeUpdate(); - } - // Get current time without ms - long time = System.currentTimeMillis() / 1000; - // Update user_regdate - sql = "UPDATE " + tableName + " SET " + tableName + ".user_regdate=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setLong(1, time); - pst.setString(2, name); - pst.executeUpdate(); - } - // Update user_lastvisit - sql = "UPDATE " + tableName + " SET " + tableName + ".user_lastvisit=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setLong(1, time); - pst.setString(2, name); - pst.executeUpdate(); - } - // Increment num_users - sql = "UPDATE " + phpBbPrefix - + "config SET config_value = config_value + 1 WHERE config_name = 'num_users';"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.executeUpdate(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java deleted file mode 100644 index 8105d2e5..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/WordpressExtension.java +++ /dev/null @@ -1,84 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.OptionalInt; - -/** - * MySQL extensions for Wordpress. - */ -class WordpressExtension extends MySqlExtension { - - private final String wordpressPrefix; - - WordpressExtension(Settings settings, Columns col) { - super(settings, col); - this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); - } - - @Override - public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { - OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con); - if (authId.isPresent()) { - saveSpecifics(auth, authId.getAsInt(), con); - } - } - - /** - * Saves the required data to Wordpress tables. - * - * @param auth the player data - * @param id the player id - * @param con the sql connection - * @throws SQLException . - */ - private void saveSpecifics(PlayerAuth auth, int id, Connection con) throws SQLException { - String sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - - new UserMetaBatchAdder(pst, id) - .addMetaRow("first_name", "") - .addMetaRow("last_name", "") - .addMetaRow("nickname", auth.getNickname()) - .addMetaRow("description", "") - .addMetaRow("rich_editing", "true") - .addMetaRow("comment_shortcuts", "false") - .addMetaRow("admin_color", "fresh") - .addMetaRow("use_ssl", "0") - .addMetaRow("show_admin_bar_front", "true") - .addMetaRow(wordpressPrefix + "capabilities", "a:1:{s:10:\"subscriber\";b:1;}") - .addMetaRow(wordpressPrefix + "user_level", "0") - .addMetaRow("default_password_nag", ""); - - // Execute queries - pst.executeBatch(); - pst.clearBatch(); - } - } - - /** Helper to add batch entries to the wrapped prepared statement. */ - private static final class UserMetaBatchAdder { - - private final PreparedStatement pst; - private final int userId; - - UserMetaBatchAdder(PreparedStatement pst, int userId) { - this.pst = pst; - this.userId = userId; - } - - UserMetaBatchAdder addMetaRow(String metaKey, String metaValue) throws SQLException { - pst.setInt(1, userId); - pst.setString(2, metaKey); - pst.setString(3, metaValue); - pst.addBatch(); - return this; - } - } -} diff --git a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java b/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java deleted file mode 100644 index 8d2a1ee9..00000000 --- a/src/main/java/fr/xephi/authme/datasource/mysqlextensions/XfBcryptExtension.java +++ /dev/null @@ -1,148 +0,0 @@ -package fr.xephi.authme.datasource.mysqlextensions; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.Columns; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.security.crypts.XfBCrypt; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import java.sql.Blob; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.OptionalInt; - -/** - * Extension for XFBCRYPT. - */ -class XfBcryptExtension extends MySqlExtension { - - private final String xfPrefix; - private final int xfGroup; - - XfBcryptExtension(Settings settings, Columns col) { - super(settings, col); - this.xfPrefix = settings.getProperty(HooksSettings.XF_TABLE_PREFIX); - this.xfGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID); - } - - @Override - public void saveAuth(PlayerAuth auth, Connection con) throws SQLException { - OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con); - if (authId.isPresent()) { - updateXenforoTablesOnSave(auth, authId.getAsInt(), con); - } - } - - /** - * Updates the xenforo tables after a player auth has been saved. - * - * @param auth the player auth which was saved - * @param id the account id - * @param con connection to the database - */ - private void updateXenforoTablesOnSave(PlayerAuth auth, int id, Connection con) throws SQLException { - // Insert player password, salt in xf_user_authenticate - String sql = "INSERT INTO " + xfPrefix + "user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, id); - pst.setString(2, XfBCrypt.SCHEME_CLASS); - String serializedHash = XfBCrypt.serializeHash(auth.getPassword().getHash()); - byte[] bytes = serializedHash.getBytes(); - Blob blob = con.createBlob(); - blob.setBytes(1, bytes); - pst.setBlob(3, blob); - pst.executeUpdate(); - } - // Update player group in xf_users - sql = "UPDATE " + tableName + " SET " + tableName + ".user_group_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, xfGroup); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - } - // Update player permission combination in xf_users - sql = "UPDATE " + tableName + " SET " + tableName + ".permission_combination_id=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, xfGroup); - pst.setString(2, auth.getNickname()); - pst.executeUpdate(); - } - // Insert player privacy combination in xf_user_privacy - sql = "INSERT INTO " + xfPrefix + "user_privacy (user_id, allow_view_profile, allow_post_profile, " - + "allow_send_personal_conversation, allow_view_identities, allow_receive_news_feed) VALUES (?,?,?,?,?,?)"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, id); - pst.setString(2, "everyone"); - pst.setString(3, "members"); - pst.setString(4, "members"); - pst.setString(5, "everyone"); - pst.setString(6, "everyone"); - pst.executeUpdate(); - } - // Insert player group relation in xf_user_group_relation - sql = "INSERT INTO " + xfPrefix + "user_group_relation (user_id, user_group_id, is_primary) VALUES (?,?,?)"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setInt(1, id); - pst.setInt(2, xfGroup); - pst.setString(3, "1"); - pst.executeUpdate(); - } - } - - @Override - public void extendAuth(PlayerAuth auth, int id, Connection con) throws SQLException { - try (PreparedStatement pst = con.prepareStatement( - "SELECT data FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;")) { - pst.setInt(1, id); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - Blob blob = rs.getBlob("data"); - byte[] bytes = blob.getBytes(1, (int) blob.length()); - auth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes))); - } - } - } - } - - @Override - public void changePassword(String user, HashedPassword password, Connection con) throws SQLException { - OptionalInt authId = retrieveIdFromTable(user, con); - if (authId.isPresent()) { - final int id = authId.getAsInt(); - // Insert password in the correct table - String sql = "UPDATE " + xfPrefix + "user_authenticate SET data=? WHERE " + col.ID + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - String serializedHash = XfBCrypt.serializeHash(password.getHash()); - byte[] bytes = serializedHash.getBytes(); - Blob blob = con.createBlob(); - blob.setBytes(1, bytes); - pst.setBlob(1, blob); - pst.setInt(2, id); - pst.executeUpdate(); - } - - // ... - sql = "UPDATE " + xfPrefix + "user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, XfBCrypt.SCHEME_CLASS); - pst.setInt(2, id); - pst.executeUpdate(); - } - } - } - - @Override - public void removeAuth(String user, Connection con) throws SQLException { - OptionalInt authId = retrieveIdFromTable(user, con); - if (authId.isPresent()) { - String sql = "DELETE FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;"; - try (PreparedStatement xfDelete = con.prepareStatement(sql)) { - xfDelete.setInt(1, authId.getAsInt()); - xfDelete.executeUpdate(); - } - } - } -} diff --git a/src/main/java/fr/xephi/authme/events/AbstractTeleportEvent.java b/src/main/java/fr/xephi/authme/events/AbstractTeleportEvent.java deleted file mode 100644 index 51d366d9..00000000 --- a/src/main/java/fr/xephi/authme/events/AbstractTeleportEvent.java +++ /dev/null @@ -1,78 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; - -/** - * Common supertype for all AuthMe teleport events. - */ -public abstract class AbstractTeleportEvent extends CustomEvent implements Cancellable { - - private final Player player; - private final Location from; - private Location to; - private boolean isCancelled; - - /** - * Constructor. - * - * @param isAsync Whether to fire the event asynchronously or not - * @param player The player - * @param to The teleport destination - */ - public AbstractTeleportEvent(boolean isAsync, Player player, Location to) { - super(isAsync); - this.player = player; - this.from = player.getLocation(); - this.to = to; - } - - /** - * Return the player planned to be teleported. - * - * @return The player - */ - public Player getPlayer() { - return player; - } - - /** - * Return the location the player is being teleported away from. - * - * @return The location prior to the teleport - */ - public Location getFrom() { - return from; - } - - /** - * Set the destination of the teleport. - * - * @param to The location to teleport the player to - */ - public void setTo(Location to) { - this.to = to; - } - - /** - * Return the destination the player is being teleported to. - * - * @return The teleport destination - */ - public Location getTo() { - return to; - } - - @Override - public void setCancelled(boolean isCancelled) { - this.isCancelled = isCancelled; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - -} diff --git a/src/main/java/fr/xephi/authme/events/AbstractUnregisterEvent.java b/src/main/java/fr/xephi/authme/events/AbstractUnregisterEvent.java deleted file mode 100644 index ac07b2ce..00000000 --- a/src/main/java/fr/xephi/authme/events/AbstractUnregisterEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; - -/** - * Event fired when a player has been unregistered. - */ -public abstract class AbstractUnregisterEvent extends CustomEvent { - - private final Player player; - - /** - * Constructor for a player that has unregistered himself. - * - * @param player the player - * @param isAsync if the event is called asynchronously - */ - public AbstractUnregisterEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - } - - /** - * Returns the player that has been unregistered. - *

- * This may be {@code null}! Please refer to the implementations of this class for details. - * - * @return the unregistered player, or null - */ - public Player getPlayer() { - return player; - } -} diff --git a/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreLoginEvent.java b/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreLoginEvent.java deleted file mode 100644 index dd2e21c3..00000000 --- a/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreLoginEvent.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * 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. - */ -public class AuthMeAsyncPreLoginEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - private boolean canLogin = true; - - /** - * Constructor. - * - * @param player The player - * @param isAsync True if the event is async, false otherwise - */ - public AuthMeAsyncPreLoginEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - } - - /** - * Return the player concerned by this event. - * - * @return The player who executed a valid {@code /login} command - */ - public Player getPlayer() { - return player; - } - - /** - * Return whether the player is allowed to log in. - * - * @return True if the player can log in, false otherwise - */ - public boolean canLogin() { - return canLogin; - } - - /** - * Define whether or not the player may log in. - * - * @param canLogin True to allow the player to log in; false to prevent him - */ - public void setCanLogin(boolean canLogin) { - this.canLogin = canLogin; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java b/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java deleted file mode 100644 index af26ad51..00000000 --- a/src/main/java/fr/xephi/authme/events/AuthMeAsyncPreRegisterEvent.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * This event is called when a player uses the register command, - * it's fired even when a user does a /register with invalid arguments. - * {@link #setCanRegister(boolean) event.setCanRegister(false)} prevents the player from registering. - */ -public class AuthMeAsyncPreRegisterEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - private boolean canRegister = true; - - /** - * Constructor. - * - * @param player The player - * @param isAsync True if the event is async, false otherwise - */ - public AuthMeAsyncPreRegisterEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - } - - /** - * Return the player concerned by this event. - * - * @return The player who executed a valid {@code /login} command - */ - public Player getPlayer() { - return player; - } - - /** - * Return whether the player is allowed to register. - * - * @return True if the player can log in, false otherwise - */ - public boolean canRegister() { - return canRegister; - } - - /** - * Define whether or not the player may register. - * - * @param canRegister True to allow the player to log in; false to prevent him - */ - public void setCanRegister(boolean canRegister) { - this.canRegister = canRegister; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/AuthMeTeleportEvent.java b/src/main/java/fr/xephi/authme/events/AuthMeTeleportEvent.java deleted file mode 100644 index ed8a08d3..00000000 --- a/src/main/java/fr/xephi/authme/events/AuthMeTeleportEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * This event is fired before AuthMe teleports a player for general purposes. - */ -public class AuthMeTeleportEvent extends AbstractTeleportEvent { - - private static final HandlerList handlers = new HandlerList(); - - /** - * Constructor. - * - * @param player The player - * @param to The teleport destination - */ - public AuthMeTeleportEvent(Player player, Location to) { - super(false, player, to); - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/CustomEvent.java b/src/main/java/fr/xephi/authme/events/CustomEvent.java deleted file mode 100644 index f647b6d5..00000000 --- a/src/main/java/fr/xephi/authme/events/CustomEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.event.Event; - -/** - * The parent of all AuthMe events. - */ -public abstract class CustomEvent extends Event { - - /** - * Constructor. - */ - public CustomEvent() { - super(false); - } - - /** - * Constructor, specifying whether the event is asynchronous or not. - * - * @param isAsync {@code true} to fire the event asynchronously, false otherwise - * @see Event#Event(boolean) - */ - public CustomEvent(boolean isAsync) { - super(isAsync); - } - -} diff --git a/src/main/java/fr/xephi/authme/events/EmailChangedEvent.java b/src/main/java/fr/xephi/authme/events/EmailChangedEvent.java deleted file mode 100644 index e489c202..00000000 --- a/src/main/java/fr/xephi/authme/events/EmailChangedEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * This event is called when a player adds or changes his email address. - */ -public class EmailChangedEvent extends CustomEvent implements Cancellable { - private static final HandlerList handlers = new HandlerList(); - private final Player player; - private final String oldEmail; - private final String newEmail; - private boolean isCancelled; - - /** - * Constructor - * - * @param player The player that changed email - * @param oldEmail Old email player had on file. Can be null when user adds an email - * @param newEmail New email that player tries to set. In case of adding email, this will contain - * the email is trying to set. - * @param isAsync should this event be called asynchronously? - */ - public EmailChangedEvent(Player player, String oldEmail, String newEmail, boolean isAsync) { - super(isAsync); - this.player = player; - this.oldEmail = oldEmail; - this.newEmail = newEmail; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - /** - * Gets the player who changes the email - * - * @return The player who changed the email - */ - public Player getPlayer() { - return player; - } - - /** - * Gets the old email in case user tries to change existing email. - * - * @return old email stored on file. Can be null when user never had an email and adds a new one. - */ - public String getOldEmail() { - return this.oldEmail; - } - - /** - * Gets the new email. - * - * @return the email user is trying to set. If user adds email and never had one before, - * this is where such email can be found. - */ - public String getNewEmail() { - return this.newEmail; - } - - @Override - public void setCancelled(boolean cancelled) { - this.isCancelled = cancelled; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/main/java/fr/xephi/authme/events/FailedLoginEvent.java b/src/main/java/fr/xephi/authme/events/FailedLoginEvent.java deleted file mode 100644 index c80ce65b..00000000 --- a/src/main/java/fr/xephi/authme/events/FailedLoginEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Event fired when a player enters a wrong password. - */ -public class FailedLoginEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - - /** - * Constructor. - * - * @param player The player - * @param isAsync if the event is called asynchronously - */ - public FailedLoginEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - } - - /** - * @return The player entering a wrong password - */ - public Player getPlayer() { - return player; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/java/fr/xephi/authme/events/FirstSpawnTeleportEvent.java b/src/main/java/fr/xephi/authme/events/FirstSpawnTeleportEvent.java deleted file mode 100644 index e5e6868d..00000000 --- a/src/main/java/fr/xephi/authme/events/FirstSpawnTeleportEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Event that is called if a player is teleported to the AuthMe first spawn, i.e. to the - * spawn location for players who have never played before. - */ -public class FirstSpawnTeleportEvent extends AbstractTeleportEvent { - - private static final HandlerList handlers = new HandlerList(); - - /** - * Constructor. - * - * @param player The player - * @param to The teleport destination - */ - public FirstSpawnTeleportEvent(Player player, Location to) { - super(false, player, to); - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/LoginEvent.java b/src/main/java/fr/xephi/authme/events/LoginEvent.java deleted file mode 100644 index eb38d626..00000000 --- a/src/main/java/fr/xephi/authme/events/LoginEvent.java +++ /dev/null @@ -1,58 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Event fired when a player has successfully logged in or registered. - */ -public class LoginEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - - /** - * Constructor. - * - * @param player The player - */ - public LoginEvent(Player player) { - this.player = player; - } - - /** - * Return the player that has successfully logged in or registered. - * - * @return The player - */ - public Player getPlayer() { - 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 - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/LogoutEvent.java b/src/main/java/fr/xephi/authme/events/LogoutEvent.java deleted file mode 100644 index 70fae096..00000000 --- a/src/main/java/fr/xephi/authme/events/LogoutEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * This event is called when a player logs out through AuthMe, i.e. only when the player - * has executed the {@code /logout} command. This event is not fired if a player simply - * leaves the server. - */ -public class LogoutEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - - /** - * Constructor. - * - * @param player The player - */ - public LogoutEvent(Player player) { - this.player = player; - } - - /** - * Return the player who logged out. - * - * @return The player - */ - public Player getPlayer() { - return this.player; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/PasswordEncryptionEvent.java b/src/main/java/fr/xephi/authme/events/PasswordEncryptionEvent.java deleted file mode 100644 index 2ad87226..00000000 --- a/src/main/java/fr/xephi/authme/events/PasswordEncryptionEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.xephi.authme.events; - -import fr.xephi.authme.security.crypts.EncryptionMethod; -import org.bukkit.event.HandlerList; - -/** - * This event is called when we need to compare or hash a password for a player and allows - * third-party listeners to change the encryption method. This is typically - * done with the {@link fr.xephi.authme.security.HashAlgorithm#CUSTOM} setting. - */ -public class PasswordEncryptionEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private EncryptionMethod method; - - /** - * Constructor. - * - * @param method The method used to encrypt the password - */ - public PasswordEncryptionEvent(EncryptionMethod method) { - super(false); - this.method = method; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link org.bukkit.event.Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - /** - * Return the encryption method used to hash the password. - * - * @return The encryption method - */ - public EncryptionMethod getMethod() { - return method; - } - - /** - * Set the encryption method to hash the password with. - * - * @param method The encryption method to use - */ - public void setMethod(EncryptionMethod method) { - this.method = method; - } -} diff --git a/src/main/java/fr/xephi/authme/events/ProtectInventoryEvent.java b/src/main/java/fr/xephi/authme/events/ProtectInventoryEvent.java deleted file mode 100644 index f2fba487..00000000 --- a/src/main/java/fr/xephi/authme/events/ProtectInventoryEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.inventory.ItemStack; - -/** - * This event is called before the inventory data of a player is suppressed, - * i.e. the inventory of the player is not displayed until he has authenticated. - */ -public class ProtectInventoryEvent extends CustomEvent implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - private final ItemStack[] storedInventory; - private final ItemStack[] storedArmor; - private final Player player; - private boolean isCancelled; - - /** - * Constructor. - * - * @param player The player - * @param isAsync True if the event is async, false otherwise - */ - public ProtectInventoryEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - this.storedInventory = player.getInventory().getContents(); - this.storedArmor = player.getInventory().getArmorContents(); - } - - /** - * Return the inventory of the player. - * - * @return The player's inventory - */ - public ItemStack[] getStoredInventory() { - return storedInventory; - } - - /** - * Return the armor of the player. - * - * @return The player's armor - */ - public ItemStack[] getStoredArmor() { - return storedArmor; - } - - /** - * Return the player whose inventory will be hidden. - * - * @return The player associated with this event - */ - public Player getPlayer() { - return player; - } - - @Override - public void setCancelled(boolean isCancelled) { - this.isCancelled = isCancelled; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/RegisterEvent.java b/src/main/java/fr/xephi/authme/events/RegisterEvent.java deleted file mode 100644 index 2a98d054..00000000 --- a/src/main/java/fr/xephi/authme/events/RegisterEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Event fired when a player has successfully registered. - */ -public class RegisterEvent extends CustomEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - - /** - * Constructor. - * - * @param player The player - */ - public RegisterEvent(Player player) { - this.player = player; - } - - /** - * Return the player that has successfully logged in or registered. - * - * @return The player - */ - public Player getPlayer() { - return player; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/RestoreInventoryEvent.java b/src/main/java/fr/xephi/authme/events/RestoreInventoryEvent.java deleted file mode 100644 index eb9bf71d..00000000 --- a/src/main/java/fr/xephi/authme/events/RestoreInventoryEvent.java +++ /dev/null @@ -1,60 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * This event is fired when the inventory of a player is restored - * (the inventory data is no longer hidden from the user). - */ -public class RestoreInventoryEvent extends CustomEvent implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - private boolean isCancelled; - - /** - * Constructor. - * - * @param player The player - */ - public RestoreInventoryEvent(Player player) { - this.player = player; - } - - /** - * Return the player whose inventory will be restored. - * - * @return Player - */ - public Player getPlayer() { - return player; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - @Override - public void setCancelled(boolean isCancelled) { - this.isCancelled = isCancelled; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/RestoreSessionEvent.java b/src/main/java/fr/xephi/authme/events/RestoreSessionEvent.java deleted file mode 100644 index abfffaa9..00000000 --- a/src/main/java/fr/xephi/authme/events/RestoreSessionEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.HandlerList; - -/** - * Event fired before a session is restored. - */ -public class RestoreSessionEvent extends CustomEvent implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - private final Player player; - private boolean isCancelled; - - public RestoreSessionEvent(Player player, boolean isAsync) { - super(isAsync); - this.player = player; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - @Override - public void setCancelled(boolean isCancelled) { - this.isCancelled = isCancelled; - } - - /** - * @return the player for which the session will be enabled - */ - public Player getPlayer() { - return player; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link org.bukkit.event.Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/java/fr/xephi/authme/events/SpawnTeleportEvent.java b/src/main/java/fr/xephi/authme/events/SpawnTeleportEvent.java deleted file mode 100644 index a1a85d84..00000000 --- a/src/main/java/fr/xephi/authme/events/SpawnTeleportEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Called if a player is teleported to a specific spawn upon joining or logging in. - */ -public class SpawnTeleportEvent extends AbstractTeleportEvent { - - private static final HandlerList handlers = new HandlerList(); - private final boolean isAuthenticated; - - /** - * Constructor. - * - * @param player The player - * @param to The teleport destination - * @param isAuthenticated Whether or not the player is logged in - */ - public SpawnTeleportEvent(Player player, Location to, boolean isAuthenticated) { - super(false, player, to); - this.isAuthenticated = isAuthenticated; - } - - /** - * Return whether or not the player is authenticated. - * - * @return true if the player is logged in, false otherwise - */ - public boolean isAuthenticated() { - return isAuthenticated; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} diff --git a/src/main/java/fr/xephi/authme/events/UnregisterByAdminEvent.java b/src/main/java/fr/xephi/authme/events/UnregisterByAdminEvent.java deleted file mode 100644 index f12e5116..00000000 --- a/src/main/java/fr/xephi/authme/events/UnregisterByAdminEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; - -/** - * Event fired after a player has been unregistered from an external source (by an admin or via the API). - *

- * Note that only the {@code playerName} is guaranteed to be not {@code null} in any case. - *

- * The {@code player} may be null if a name is supplied which has never been online on the server – - * due to migrations, data removal, etc. it is possible that a user exists in the database for which the - * server knows no {@link Player} object. - *

- * If a player is unregistered via an API call, the {@code initiator} is null as the action has not been - * started by any {@link CommandSender}. Otherwise, the {@code initiator} is the user who performed the - * command to unregister the player name. - */ -public class UnregisterByAdminEvent extends AbstractUnregisterEvent { - - private static final HandlerList handlers = new HandlerList(); - private final String playerName; - private final CommandSender initiator; - - /** - * Constructor. - * - * @param player the player (may be null - see class JavaDoc) - * @param playerName the name of the player that was unregistered - * @param isAsync whether or not the event is async - * @param initiator the initiator of the unregister process (may be null - see class JavaDoc) - */ - public UnregisterByAdminEvent(Player player, String playerName, boolean isAsync, CommandSender initiator) { - super(player, isAsync); - this.playerName = playerName; - this.initiator = initiator; - } - - /** - * @return the name of the player that was unregistered - */ - public String getPlayerName() { - return playerName; - } - - /** - * @return the user who requested to unregister the name, or null if not applicable - */ - public CommandSender getInitiator() { - return initiator; - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link org.bukkit.event.Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/java/fr/xephi/authme/events/UnregisterByPlayerEvent.java b/src/main/java/fr/xephi/authme/events/UnregisterByPlayerEvent.java deleted file mode 100644 index cd96cd91..00000000 --- a/src/main/java/fr/xephi/authme/events/UnregisterByPlayerEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.xephi.authme.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; - -/** - * Event fired after a player has unregistered himself. - */ -public class UnregisterByPlayerEvent extends AbstractUnregisterEvent { - - private static final HandlerList handlers = new HandlerList(); - - /** - * Constructor. - * - * @param player the player (never null) - * @param isAsync if the event is called asynchronously - */ - public UnregisterByPlayerEvent(Player player, boolean isAsync) { - super(player, isAsync); - } - - /** - * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link org.bukkit.event.Event}. - * - * @return The list of handlers - */ - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/java/fr/xephi/authme/initialization/DataFolder.java b/src/main/java/fr/xephi/authme/initialization/DataFolder.java deleted file mode 100644 index 0288f45a..00000000 --- a/src/main/java/fr/xephi/authme/initialization/DataFolder.java +++ /dev/null @@ -1,14 +0,0 @@ -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 { -} diff --git a/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java b/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java deleted file mode 100644 index 41e48f3f..00000000 --- a/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java +++ /dev/null @@ -1,115 +0,0 @@ -package fr.xephi.authme.initialization; - -import com.alessiodp.libby.Library; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.CacheDataSource; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.datasource.H2; -import fr.xephi.authme.datasource.MariaDB; -import fr.xephi.authme.datasource.MySQL; -import fr.xephi.authme.datasource.PostgreSqlDataSource; -import fr.xephi.authme.datasource.SQLite; -import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; - -import javax.inject.Inject; -import javax.inject.Provider; -import java.io.File; -import java.sql.SQLException; - -import static fr.xephi.authme.AuthMe.libraryManager; - -/** - * Creates the AuthMe data source. - */ -public class DataSourceProvider implements Provider { - - private static final int SQLITE_MAX_SIZE = 4000; - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(DataSourceProvider.class); - - @Inject - @DataFolder - private File dataFolder; - @Inject - private Settings settings; - @Inject - private BukkitService bukkitService; - @Inject - private PlayerCache playerCache; - @Inject - private MySqlExtensionsFactory mySqlExtensionsFactory; - - DataSourceProvider() { - } - - @Override - public DataSource get() { - try { - return createDataSource(); - } catch (Exception e) { - logger.logException("Could not create data source:", e); - throw new IllegalStateException("Error during initialization of data source", e); - } - } - - /** - * Sets up the data source. - * - * @return the constructed data source - * @throws SQLException when initialization of a SQL data source failed - */ - private DataSource createDataSource() throws SQLException { - DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND); - DataSource dataSource; - switch (dataSourceType) { - case MYSQL: - dataSource = new MySQL(settings, mySqlExtensionsFactory); - break; - case MARIADB: - dataSource = new MariaDB(settings, mySqlExtensionsFactory); - break; - case POSTGRESQL: - dataSource = new PostgreSqlDataSource(settings, mySqlExtensionsFactory); - break; - case SQLITE: - dataSource = new SQLite(settings, dataFolder); - break; - case H2: - Library h2 = Library.builder() - .groupId("com.h2database") - .artifactId("h2") - .version("2.2.224") - .build(); - libraryManager.addMavenCentral(); - libraryManager.loadLibrary(h2); - dataSource = new H2(settings, dataFolder); - break; - default: - throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'"); - } - - if (settings.getProperty(DatabaseSettings.USE_CACHING)) { - dataSource = new CacheDataSource(dataSource, playerCache); - } - if (DataSourceType.SQLITE.equals(dataSourceType)) { - checkDataSourceSize(dataSource); - } - return dataSource; - } - - private void checkDataSourceSize(DataSource dataSource) { - bukkitService.runTaskAsynchronously(() -> { - int accounts = dataSource.getAccountsRegistered(); - if (accounts >= SQLITE_MAX_SIZE) { - logger.warning("YOU'RE USING THE SQLITE DATABASE WITH " - + accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!"); - } - }); - } -} diff --git a/src/main/java/fr/xephi/authme/initialization/HasCleanup.java b/src/main/java/fr/xephi/authme/initialization/HasCleanup.java deleted file mode 100644 index 351df4f6..00000000 --- a/src/main/java/fr/xephi/authme/initialization/HasCleanup.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.initialization; - -/** - * Common interface for types which have data that becomes outdated - * and that can be cleaned up periodically. - * - * @see fr.xephi.authme.task.CleanupTask - */ -public interface HasCleanup { - - /** - * Performs the cleanup action. - */ - void performCleanup(); - -} diff --git a/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java b/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java deleted file mode 100644 index 261e7dd5..00000000 --- a/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.initialization; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -/** - * Saves all players' data when the plugin shuts down. - */ -public class OnShutdownPlayerSaver { - - @Inject - private BukkitService bukkitService; - @Inject - private Settings settings; - @Inject - private ValidationService validationService; - @Inject - private DataSource dataSource; - @Inject - private SpawnLoader spawnLoader; - @Inject - private PlayerCache playerCache; - @Inject - private LimboService limboService; - - OnShutdownPlayerSaver() { - } - - /** - * Saves the data of all online players. - */ - public void saveAllPlayers() { - for (Player player : bukkitService.getOnlinePlayers()) { - savePlayer(player); - } - } - - private void savePlayer(Player player) { - String name = player.getName().toLowerCase(Locale.ROOT); - if (PlayerUtils.isNpc(player) || validationService.isUnrestricted(name)) { - return; - } - if (limboService.hasLimboPlayer(name)) { - limboService.restoreData(player); - } else { - saveLoggedinPlayer(player); - } - playerCache.removePlayer(name); - } - - private void saveLoggedinPlayer(Player player) { - if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { - Location loc = spawnLoader.getPlayerLocationOrSpawn(player); - PlayerAuth auth = PlayerAuth.builder() - .name(player.getName().toLowerCase(Locale.ROOT)) - .realName(player.getName()) - .location(loc).build(); - dataSource.updateQuitLoc(auth); - // TODO: send an update when a messaging service will be implemented (QUITLOC) - } - } -} diff --git a/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java b/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java deleted file mode 100644 index 705f3bcc..00000000 --- a/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java +++ /dev/null @@ -1,114 +0,0 @@ -package fr.xephi.authme.initialization; - -import com.github.Anon8281.universalScheduler.UniversalRunnable; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleFilter; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.output.Log4JFilter; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.apache.logging.log4j.LogManager; -import org.bstats.bukkit.Metrics; -import org.bstats.charts.SimplePie; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; -import java.util.logging.Logger; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE; -import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS; - -/** - * Contains actions such as migrations that should be performed on startup. - */ -public class OnStartupTasks { - - private static ConsoleLogger consoleLogger = ConsoleLoggerFactory.get(OnStartupTasks.class); - - @Inject - private DataSource dataSource; - @Inject - private Settings settings; - @Inject - private BukkitService bukkitService; - @Inject - private Messages messages; - - OnStartupTasks() { - } - - /** - * Sends bstats metrics. - * - * @param plugin the plugin instance - * @param settings the settings - */ - public static void sendMetrics(AuthMe plugin, Settings settings) { - final Metrics metrics = new Metrics(plugin, 18479); - - metrics.addCustomChart(new SimplePie("messages_language", - () -> settings.getProperty(PluginSettings.MESSAGES_LANGUAGE))); - metrics.addCustomChart(new SimplePie("database_backend", - () -> settings.getProperty(DatabaseSettings.BACKEND).toString())); - } - - /** - * Sets up the console filter if enabled. - * - * @param logger the plugin logger - */ - public static void setupConsoleFilter(Logger logger) { - // Try to set the log4j filter - try { - Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter"); - setLog4JFilter(); - } catch (ClassNotFoundException | NoClassDefFoundError e) { - // log4j is not available - consoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled"); - ConsoleFilter filter = new ConsoleFilter(); - logger.setFilter(filter); - Bukkit.getLogger().setFilter(filter); - Logger.getLogger("Minecraft").setFilter(filter); - } - } - - // Set the console filter to remove the passwords - private static void setLog4JFilter() { - org.apache.logging.log4j.core.Logger logger; - logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); - logger.addFilter(new Log4JFilter()); - } - - /** - * Starts a task that regularly reminds players without a defined email to set their email, - * if enabled. - */ - public void scheduleRecallEmailTask() { - if (!settings.getProperty(RECALL_PLAYERS)) { - return; - } - bukkitService.runTaskTimerAsynchronously(new UniversalRunnable() { - @Override - public void run() { - List loggedPlayersWithEmptyMail = dataSource.getLoggedPlayersWithEmptyMail(); - bukkitService.runTask(() -> { - for (String playerWithoutMail : loggedPlayersWithEmptyMail) { - Player player = bukkitService.getPlayerExact(playerWithoutMail); - if (player != null) { - messages.send(player, MessageKey.ADD_EMAIL_MESSAGE); - } - } - }); - } - }, 1, (long) TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL)); - } -} diff --git a/src/main/java/fr/xephi/authme/initialization/Reloadable.java b/src/main/java/fr/xephi/authme/initialization/Reloadable.java deleted file mode 100644 index 65c3a337..00000000 --- a/src/main/java/fr/xephi/authme/initialization/Reloadable.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.xephi.authme.initialization; - -/** - * Interface for reloadable entities. - * - * @see fr.xephi.authme.command.executable.authme.ReloadCommand - */ -public interface Reloadable { - - /** - * Performs the reload action. - */ - void reload(); - -} diff --git a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java b/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java deleted file mode 100644 index 89d18318..00000000 --- a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.xephi.authme.initialization; - -import fr.xephi.authme.settings.Settings; - -/** - * Interface for classes that keep a local copy of certain settings. - * - * @see fr.xephi.authme.command.executable.authme.ReloadCommand - */ -public interface SettingsDependent { - - /** - * Performs a reload with the provided settings instance. - * - * @param settings the settings instance - */ - void reload(Settings settings); -} diff --git a/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java b/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java deleted file mode 100644 index 77133715..00000000 --- a/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.xephi.authme.initialization; - -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.resource.PropertyResource; -import fr.xephi.authme.service.yaml.YamlFileResourceProvider; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SettingsMigrationService; -import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever; -import fr.xephi.authme.util.FileUtils; - -import javax.inject.Inject; -import javax.inject.Provider; -import java.io.File; - -/** - * Initializes the settings. - */ -public class SettingsProvider implements Provider { - - @Inject - @DataFolder - private File dataFolder; - @Inject - private SettingsMigrationService migrationService; - - SettingsProvider() { - } - - /** - * Loads the plugin's settings. - * - * @return the settings instance, or null if it could not be constructed - */ - @Override - public Settings get() { - File configFile = new File(dataFolder, "config.yml"); - if (!configFile.exists()) { - FileUtils.create(configFile); - } - PropertyResource resource = YamlFileResourceProvider.loadFromFile(configFile); - ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData(); - return new Settings(dataFolder, resource, migrationService, configurationData); - } - -} diff --git a/src/main/java/fr/xephi/authme/initialization/TaskCloser.java b/src/main/java/fr/xephi/authme/initialization/TaskCloser.java deleted file mode 100644 index 4cd6daa9..00000000 --- a/src/main/java/fr/xephi/authme/initialization/TaskCloser.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.xephi.authme.initialization; - -import com.github.Anon8281.universalScheduler.scheduling.schedulers.TaskScheduler; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.datasource.DataSource; - -/** - * Waits for asynchronous tasks to complete before closing the data source - * so the plugin can shut down properly. - */ -public class TaskCloser implements Runnable { - - private final TaskScheduler scheduler; - private final DataSource dataSource; - - /** - * Constructor. - * - * @param dataSource the data source (nullable) - */ - public TaskCloser(DataSource dataSource) { - this.scheduler = AuthMe.getScheduler(); - this.dataSource = dataSource; - } - - @Override - public void run() { - scheduler.cancelTasks(); - if (dataSource != null) { - dataSource.closeConnection(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/AdvancedShulkerFixListener.java b/src/main/java/fr/xephi/authme/listener/AdvancedShulkerFixListener.java deleted file mode 100644 index 64045591..00000000 --- a/src/main/java/fr/xephi/authme/listener/AdvancedShulkerFixListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockDispenseEvent; - -//This fix is only for Minecraft 1.13- -public class AdvancedShulkerFixListener implements Listener { - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onDispenserActivate(BlockDispenseEvent event) { - Block block = event.getBlock(); - - if (block.getY() <= 0 || block.getY() >= block.getWorld().getMaxHeight() - 1) { - event.setCancelled(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/BedrockAutoLoginListener.java b/src/main/java/fr/xephi/authme/listener/BedrockAutoLoginListener.java deleted file mode 100644 index 4f63e610..00000000 --- a/src/main/java/fr/xephi/authme/listener/BedrockAutoLoginListener.java +++ /dev/null @@ -1,54 +0,0 @@ -package fr.xephi.authme.listener; -/* Inspired by DongShaoNB/BedrockPlayerSupport **/ - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.api.v3.AuthMeApi; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -import javax.inject.Inject; -import java.util.UUID; - -import static org.bukkit.Bukkit.getServer; - -public class BedrockAutoLoginListener implements Listener { - private final AuthMeApi authmeApi = AuthMeApi.getInstance(); - @Inject - private BukkitService bukkitService; - @Inject - private AuthMe plugin; - @Inject - private Messages messages; - - @Inject - private Settings settings; - - public BedrockAutoLoginListener() { - } - - private boolean isBedrockPlayer(UUID uuid) { - return settings.getProperty(HooksSettings.HOOK_FLOODGATE_PLAYER) && settings.getProperty(SecuritySettings.FORCE_LOGIN_BEDROCK) && org.geysermc.floodgate.api.FloodgateApi.getInstance().isFloodgateId(uuid) && getServer().getPluginManager().getPlugin("floodgate") != null; - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - String name = event.getPlayer().getName(); - UUID uuid = event.getPlayer().getUniqueId(); - bukkitService.runTaskLater(player, () -> { - if (isBedrockPlayer(uuid) && !authmeApi.isAuthenticated(player) && authmeApi.isRegistered(name)) { - authmeApi.forceLogin(player, true); - messages.send(player, MessageKey.BEDROCK_AUTO_LOGGED_IN); - } - },20L); - } -} diff --git a/src/main/java/fr/xephi/authme/listener/BlockListener.java b/src/main/java/fr/xephi/authme/listener/BlockListener.java deleted file mode 100644 index e40bf8d0..00000000 --- a/src/main/java/fr/xephi/authme/listener/BlockListener.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockPlaceEvent; - -import javax.inject.Inject; - -public class BlockListener implements Listener { - - @Inject - private ListenerService listenerService; - - @EventHandler(ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent event) { - if (listenerService.shouldCancelEvent(event.getPlayer())) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true) - public void onBlockBreak(BlockBreakEvent event) { - if (listenerService.shouldCancelEvent(event.getPlayer())) { - event.setCancelled(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/DoubleLoginFixListener.java b/src/main/java/fr/xephi/authme/listener/DoubleLoginFixListener.java deleted file mode 100644 index 2c0370a4..00000000 --- a/src/main/java/fr/xephi/authme/listener/DoubleLoginFixListener.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.listener; -//Prevent Ghost Players - -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.service.CommonService; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -import javax.inject.Inject; -import java.util.Collection; -import java.util.HashSet; - -public class DoubleLoginFixListener implements Listener { - @Inject - private CommonService service; - - public DoubleLoginFixListener() { - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Collection PlayerList = Bukkit.getServer().getOnlinePlayers(); - HashSet PlayerSet = new HashSet(); - for (Player ep : PlayerList) { - if (PlayerSet.contains(ep.getName().toLowerCase())) { - ep.kickPlayer(service.retrieveSingleMessage(ep.getPlayer(), MessageKey.DOUBLE_LOGIN_FIX)); - break; - } - PlayerSet.add(ep.getName().toLowerCase()); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/EntityListener.java b/src/main/java/fr/xephi/authme/listener/EntityListener.java deleted file mode 100644 index 35e10920..00000000 --- a/src/main/java/fr/xephi/authme/listener/EntityListener.java +++ /dev/null @@ -1,99 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityInteractEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.EntityShootBowEvent; -import org.bukkit.event.entity.EntityTargetEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.projectiles.ProjectileSource; - -import javax.inject.Inject; - -public class EntityListener implements Listener { - - private final ListenerService listenerService; - - @Inject - EntityListener(ListenerService listenerService) { - this.listenerService = listenerService; - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onDamage(EntityDamageEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.getEntity().setFireTicks(0); - event.setDamage(0); - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onAttack(EntityDamageByEntityEvent event) { - if (listenerService.shouldCancelEvent(event.getDamager())) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onEntityTarget(EntityTargetEvent event) { - if (listenerService.shouldCancelEvent(event.getTarget())) { - event.setTarget(null); - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onFoodLevelChange(FoodLevelChangeEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void entityRegainHealthEvent(EntityRegainHealthEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setAmount(0); - event.setCancelled(true); - } - } - - //TODO sgdc3 20190808: We listen at the same event twice, does it make any sense? - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onEntityInteract(EntityInteractEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onLowestEntityInteract(EntityInteractEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onProjectileLaunch(ProjectileLaunchEvent event) { - final Projectile projectile = event.getEntity(); - - ProjectileSource shooter = projectile.getShooter(); - if (shooter instanceof Player && listenerService.shouldCancelEvent((Player) shooter)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) - public void onShoot(EntityShootBowEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java b/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java deleted file mode 100644 index 0b887f92..00000000 --- a/src/main/java/fr/xephi/authme/listener/FailedVerificationException.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.message.MessageKey; - -/** - * Exception thrown when a verification has failed. - */ -public class FailedVerificationException extends Exception { - - private static final long serialVersionUID = 3903242223297960699L; - 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 - + ";args=" + (args == null ? "null" : String.join(", ", args)); - } -} diff --git a/src/main/java/fr/xephi/authme/listener/ListenerService.java b/src/main/java/fr/xephi/authme/listener/ListenerService.java deleted file mode 100644 index 3d582b0e..00000000 --- a/src/main/java/fr/xephi/authme/listener/ListenerService.java +++ /dev/null @@ -1,104 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityEvent; -import org.bukkit.event.player.PlayerEvent; - -import javax.inject.Inject; - -/** - * Service class for the AuthMe listeners to determine whether an event should be canceled. - */ -class ListenerService implements SettingsDependent { - private final DataSource dataSource; - private final PlayerCache playerCache; - private final ValidationService validationService; - private boolean isRegistrationForced; - - - @Inject - ListenerService(Settings settings, DataSource dataSource, PlayerCache playerCache, - ValidationService validationService) { - this.dataSource = dataSource; - this.playerCache = playerCache; - this.validationService = validationService; - reload(settings); - } - - /** - * Returns whether an event should be canceled (for unauthenticated, non-NPC players). - * - * @param event the event to process - * @return true if the event should be canceled, false otherwise - */ - public boolean shouldCancelEvent(EntityEvent event) { - Entity entity = event.getEntity(); - return shouldCancelEvent(entity); - } - - /** - * Returns, based on the entity associated with the event, whether or not the event should be canceled. - * - * @param entity the player entity to verify - * @return true if the associated event should be canceled, false otherwise - */ - public boolean shouldCancelEvent(Entity entity) { - if (entity instanceof Player) { - Player player = (Player) entity; - return shouldCancelEvent(player); - } - return false; - } - - /** - * Returns whether an event should be canceled (for unauthenticated, non-NPC players). - * - * @param event the event to process - * @return true if the event should be canceled, false otherwise - */ - public boolean shouldCancelEvent(PlayerEvent event) { - Player player = event.getPlayer(); - return shouldCancelEvent(player); - } - - /** - * Returns, based on the player associated with the event, whether or not the event should be canceled. - * - * @param player the player to verify - * @return true if the associated event should be canceled, false otherwise - */ - - public boolean shouldCancelEvent(Player player) { - - return player != null && !checkAuth(player.getName()) && !PlayerUtils.isNpc(player); - } - @Override - public void reload(Settings settings) { - isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE); - } - - /** - * 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 (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)){ - return true; - } - if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) { - return true; - } - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/listener/LoginLocationFixListener.java b/src/main/java/fr/xephi/authme/listener/LoginLocationFixListener.java deleted file mode 100644 index 1c64b68b..00000000 --- a/src/main/java/fr/xephi/authme/listener/LoginLocationFixListener.java +++ /dev/null @@ -1,118 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.api.v3.AuthMeApi; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.TeleportUtils; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; - -import javax.inject.Inject; -import java.lang.reflect.Method; - - -public class LoginLocationFixListener implements Listener { - @Inject - private AuthMe plugin; - @Inject - private Messages messages; - @Inject - private Settings settings; - private final AuthMeApi authmeApi = AuthMeApi.getInstance(); - - public LoginLocationFixListener() { - } - - private static Material materialPortal = Material.matchMaterial("PORTAL"); - - private static boolean isAvailable; // false: unchecked/method not available true: method is available - BlockFace[] faces = {BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.SOUTH_EAST, BlockFace.SOUTH_WEST, BlockFace.NORTH_EAST, BlockFace.NORTH_WEST}; - - static { - if (materialPortal == null) { - materialPortal = Material.matchMaterial("PORTAL_BLOCK"); - if (materialPortal == null) { - materialPortal = Material.matchMaterial("NETHER_PORTAL"); - } - } - try { - Method getMinHeightMethod = World.class.getMethod("getMinHeight"); - isAvailable = true; - } catch (NoSuchMethodException e) { - isAvailable = false; - } - } - - private int getMinHeight(World world) { - //This keeps compatibility of 1.16.x and lower - if (isAvailable) { - return world.getMinHeight(); - } else { - return 0; - } - } - - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - Location JoinLocation = player.getLocation(); - if (settings.getProperty(SecuritySettings.LOGIN_LOC_FIX_SUB_PORTAL)) { - if (!JoinLocation.getBlock().getType().equals(materialPortal) && !JoinLocation.getBlock().getRelative(BlockFace.UP).getType().equals(materialPortal)) { - return; - } - Block JoinBlock = JoinLocation.getBlock(); - boolean solved = false; - for (BlockFace face : faces) { - if (JoinBlock.getRelative(face).getType().equals(Material.AIR) && JoinBlock.getRelative(face).getRelative(BlockFace.UP).getType().equals(Material.AIR)) { - TeleportUtils.teleport(player, JoinBlock.getRelative(face).getLocation().add(0.5, 0.1, 0.5)); - solved = true; - break; - } - } - if (!solved) { - JoinBlock.getRelative(BlockFace.UP).breakNaturally(); - JoinBlock.breakNaturally(); - } - messages.send(player, MessageKey.LOCATION_FIX_PORTAL); - } - if (settings.getProperty(SecuritySettings.LOGIN_LOC_FIX_SUB_UNDERGROUND)) { - Material UpType = JoinLocation.getBlock().getRelative(BlockFace.UP).getType(); - World world = player.getWorld(); - int MaxHeight = world.getMaxHeight(); - int MinHeight = getMinHeight(world); - if (!UpType.isOccluding() && !UpType.equals(Material.LAVA)) { - return; - } - for (int i = MinHeight; i <= MaxHeight; i++) { - JoinLocation.setY(i); - Block JoinBlock = JoinLocation.getBlock(); - if ((JoinBlock.getRelative(BlockFace.DOWN).getType().isBlock()) - && JoinBlock.getType().equals(Material.AIR) - && JoinBlock.getRelative(BlockFace.UP).getType().equals(Material.AIR)) { - if (JoinBlock.getRelative(BlockFace.DOWN).getType().equals(Material.LAVA)) { - JoinBlock.getRelative(BlockFace.DOWN).setType(Material.DIRT); - } - TeleportUtils.teleport(player, JoinBlock.getLocation().add(0.5, 0.1, 0.5)); - messages.send(player, MessageKey.LOCATION_FIX_UNDERGROUND); - break; - } - if (i == MaxHeight) { - TeleportUtils.teleport(player, JoinBlock.getLocation().add(0.5, 1.1, 0.5)); - messages.send(player, MessageKey.LOCATION_FIX_UNDERGROUND_CANT_FIX); - } - } - } - - } -} diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java deleted file mode 100644 index a617c2fa..00000000 --- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java +++ /dev/null @@ -1,223 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.service.AntiBotService; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.ProtectionSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Utils; -import org.bukkit.Server; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerLoginEvent; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.util.Collection; -import java.util.Locale; -import java.util.regex.Pattern; - -/** - * Service for performing various verifications when a player joins. - */ -public class OnJoinVerifier implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(OnJoinVerifier.class); - - @Inject - private Settings settings; - @Inject - private DataSource dataSource; - @Inject - private Messages messages; - @Inject - private PermissionsManager permissionsManager; - @Inject - private AntiBotService antiBotService; - @Inject - private ValidationService validationService; - @Inject - private BukkitService bukkitService; - @Inject - private Server server; - - private Pattern nicknamePattern; - - OnJoinVerifier() { - } - - - @PostConstruct - @Override - public void reload() { - String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS); - nicknamePattern = Utils.safePatternCompile(nickRegEx); - } - - /** - * Checks if Antibot is enabled. - * - * @param name the joining player name to check - * @param isAuthAvailable whether or not the player is registered - * @throws FailedVerificationException if the verification fails - */ - public void checkAntibot(String name, boolean isAuthAvailable) throws FailedVerificationException { - if (isAuthAvailable || permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)) { - return; - } - if (antiBotService.shouldKick()) { - antiBotService.addPlayerKick(name); - throw new FailedVerificationException(MessageKey.KICK_ANTIBOT); - } - } - - /** - * Checks whether non-registered players should be kicked, and if so, whether the player should be kicked. - * - * @param isAuthAvailable whether or not the player is registered - * @throws FailedVerificationException if the verification fails - */ - public void checkKickNonRegistered(boolean isAuthAvailable) throws FailedVerificationException { - if (!isAuthAvailable && settings.getProperty(RestrictionSettings.KICK_NON_REGISTERED)) { - throw new FailedVerificationException(MessageKey.MUST_REGISTER_MESSAGE); - } - } - - /** - * Checks that the name adheres to the configured username restrictions. - * - * @param name the name to verify - * @throws FailedVerificationException if the verification fails - */ - public void checkIsValidName(String name) throws FailedVerificationException { - if (name.length() > settings.getProperty(RestrictionSettings.MAX_NICKNAME_LENGTH) - || name.length() < settings.getProperty(RestrictionSettings.MIN_NICKNAME_LENGTH)) { - throw new FailedVerificationException(MessageKey.INVALID_NAME_LENGTH); - } - if (!nicknamePattern.matcher(name).matches()) { - throw new FailedVerificationException(MessageKey.INVALID_NAME_CHARACTERS, nicknamePattern.pattern()); - } - } - - /** - * Handles the case of a full server and verifies if the user's connection should really be refused - * by adjusting the event object accordingly. Attempts to kick a non-VIP player to make room if the - * joining player is a VIP. - * - * @param event the login event to verify - * - * @return true if the player's connection should be refused (i.e. the event does not need to be processed - * further), false if the player is not refused - */ - public boolean refusePlayerForFullServer(PlayerLoginEvent event) { - final Player player = event.getPlayer(); - if (event.getResult() != PlayerLoginEvent.Result.KICK_FULL) { - // Server is not full, no need to do anything - return false; - } else if (!permissionsManager.hasPermission(player, PlayerStatePermission.IS_VIP)) { - // Server is full and player is NOT VIP; set kick message and proceed with kick - event.setKickMessage(messages.retrieveSingle(player, MessageKey.KICK_FULL_SERVER)); - return true; - } - - // Server is full and player is VIP; attempt to kick a non-VIP player to make room - Collection onlinePlayers = bukkitService.getOnlinePlayers(); - if (onlinePlayers.size() < server.getMaxPlayers()) { - event.allow(); - return false; - } - Player nonVipPlayer = generateKickPlayer(onlinePlayers); - if (nonVipPlayer != null) { - // AuthMeReReloaded - Folia compatibility - bukkitService.runTaskIfFolia(nonVipPlayer, () -> nonVipPlayer.kickPlayer(messages.retrieveSingle(player, MessageKey.KICK_FOR_VIP))); - event.allow(); - return false; - } else { - logger.info("VIP player " + player.getName() + " tried to join, but the server was full"); - event.setKickMessage(messages.retrieveSingle(player, MessageKey.KICK_FULL_SERVER)); - return true; - } - } - - /** - * Checks that the casing in the username corresponds to the one in the database, if so configured. - * - * @param connectingName the player name to verify - * @param auth the auth object associated with the player - * @throws FailedVerificationException if the verification fails - */ - public void checkNameCasing(String connectingName, PlayerAuth auth) throws FailedVerificationException { - if (auth != null && settings.getProperty(RegistrationSettings.PREVENT_OTHER_CASE)) { - String realName = auth.getRealName(); // might be null or "Player" - - if (StringUtils.isBlank(realName) || "Player".equals(realName)) { - dataSource.updateRealName(connectingName.toLowerCase(Locale.ROOT), connectingName); - } else if (!realName.equals(connectingName)) { - throw new FailedVerificationException(MessageKey.INVALID_NAME_CASE, realName, connectingName); - } - } - } - - /** - * Checks that the player's country is admitted. - * - * @param name the joining player name to verify - * @param address the player address - * @param isAuthAvailable whether or not the user is registered - * @throws FailedVerificationException if the verification fails - */ - public void checkPlayerCountry(String name, String address, - boolean isAuthAvailable) throws FailedVerificationException { - if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)) - && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION) - && !permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_COUNTRY_CHECK) - && !validationService.isCountryAdmitted(address)) { - throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR); - } - } - - /** - * Checks if a player with the same name (case-insensitive) is already playing and refuses the - * connection if so configured. - * - * @param name the player name to check - * @throws FailedVerificationException if the verification fails - */ - public void checkSingleSession(String name) throws FailedVerificationException { - if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) { - return; - } - - Player onlinePlayer = bukkitService.getPlayerExact(name); - if (onlinePlayer != null) { - throw new FailedVerificationException(MessageKey.USERNAME_ALREADY_ONLINE_ERROR); - } - } - - /** - * Selects a non-VIP player to kick when a VIP player joins the server when full. - * - * @param onlinePlayers list of online players - * - * @return the player to kick, or null if none applicable - */ - private Player generateKickPlayer(Collection onlinePlayers) { - for (Player player : onlinePlayers) { - if (!permissionsManager.hasPermission(player, PlayerStatePermission.IS_VIP)) { - return player; - } - } - return null; - } -} diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener.java b/src/main/java/fr/xephi/authme/listener/PlayerListener.java deleted file mode 100644 index b24da9da..00000000 --- a/src/main/java/fr/xephi/authme/listener/PlayerListener.java +++ /dev/null @@ -1,567 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.data.QuickCommandsProtectionManager; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.AntiBotService; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.JoinMessageService; -import fr.xephi.authme.service.TeleportationService; -import fr.xephi.authme.service.ValidationService; -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.PluginSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.TeleportUtils; -import fr.xephi.authme.util.message.I18NUtils; -import fr.xephi.authme.util.message.MiniMessageUtils; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.SignChangeEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; -import org.bukkit.event.player.PlayerBedEnterEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerEditBookEvent; -import org.bukkit.event.player.PlayerFishEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerItemConsumeEvent; -import org.bukkit.event.player.PlayerItemHeldEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerRespawnEvent; -import org.bukkit.event.player.PlayerShearEntityEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryView; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS; -import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT; -import static org.bukkit.Bukkit.getServer; - -/** - * Listener class for player events. - */ -public class PlayerListener implements Listener { - @Inject - private Settings settings; - @Inject - private Messages messages; - @Inject - private DataSource dataSource; - @Inject - private AntiBotService antiBotService; - @Inject - private Management management; - @Inject - private BukkitService bukkitService; - @Inject - private SpawnLoader spawnLoader; - @Inject - private OnJoinVerifier onJoinVerifier; - @Inject - private ListenerService listenerService; - @Inject - private TeleportationService teleportationService; - @Inject - private ValidationService validationService; - @Inject - private JoinMessageService joinMessageService; - @Inject - private PermissionsManager permissionsManager; - @Inject - private QuickCommandsProtectionManager quickCommandsProtectionManager; - - public static List PENDING_INVENTORIES = new ArrayList<>(); - - // Lowest priority to apply fast protection checks - @EventHandler(priority = EventPriority.LOWEST) - public void onAsyncPlayerPreLoginEventLowest(AsyncPlayerPreLoginEvent event) { - - if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { - return; - } - final String name = event.getName(); - - // NOTE: getAddress() sometimes returning null, we don't want to handle this race condition - if (event.getAddress() == null) { - event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, - messages.retrieveSingle(name, MessageKey.KICK_UNRESOLVED_HOSTNAME)); - return; - } - - if (validationService.isUnrestricted(name)) { - return; - } - if (settings.getProperty(HooksSettings.HOOK_FLOODGATE_PLAYER) && settings.getProperty(HooksSettings.IGNORE_BEDROCK_NAME_CHECK)) { - if (getServer().getPluginManager().getPlugin("floodgate") != null) { - if (org.geysermc.floodgate.api.FloodgateApi.getInstance().isFloodgateId(event.getUniqueId())) return; - } - } - // Non-blocking checks - try { - onJoinVerifier.checkIsValidName(name); - } catch (FailedVerificationException e) { - event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs())); - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - - } - } - - /* - * Login/join/leave events - */ - - // Note: at this stage (HIGHEST priority) the user's permission data should already have been loaded by - // the permission handler, we don't need to call permissionsManager.loadUserData() - - @EventHandler(priority = EventPriority.HIGHEST) - public void onAsyncPlayerPreLoginEventHighest(AsyncPlayerPreLoginEvent event) { - if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { - return; - } - final String name = event.getName(); - - if (validationService.isUnrestricted(name)) { - return; - } - - // Slow, blocking checks - try { - final PlayerAuth auth = dataSource.getAuth(name); - final boolean isAuthAvailable = auth != null; - onJoinVerifier.checkKickNonRegistered(isAuthAvailable); - onJoinVerifier.checkAntibot(name, isAuthAvailable); - onJoinVerifier.checkNameCasing(name, auth); - final String ip = event.getAddress().getHostAddress(); - onJoinVerifier.checkPlayerCountry(name, ip, isAuthAvailable); - } catch (FailedVerificationException e) { - event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs())); - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - } - } - - // Note: We can't teleport the player in the PlayerLoginEvent listener - // as the new player location will be reverted by the server. - - @EventHandler(priority = EventPriority.LOW) - public void onPlayerLogin(PlayerLoginEvent event) { - final Player player = event.getPlayer(); - final String name = player.getName(); - - try { - onJoinVerifier.checkSingleSession(name); - } catch (FailedVerificationException e) { - event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs())); - event.setResult(PlayerLoginEvent.Result.KICK_OTHER); - return; - } - - if (validationService.isUnrestricted(name)) { - return; - } - - onJoinVerifier.refusePlayerForFullServer(event); - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerJoin(PlayerJoinEvent event) { - final Player player = event.getPlayer(); - if (!PlayerListener19Spigot.isPlayerSpawnLocationEventCalled()) { - teleportationService.teleportOnJoin(player); - } - - quickCommandsProtectionManager.processJoin(player); - - management.performJoin(player); - - teleportationService.teleportNewPlayerToFirstSpawn(player); - - } - - - @EventHandler(priority = EventPriority.HIGH) // HIGH as EssentialsX listens at HIGHEST - public void onJoinMessage(PlayerJoinEvent event) { - final Player player = event.getPlayer(); - - - // Note: join message can be null, despite api documentation says not - if (settings.getProperty(RegistrationSettings.REMOVE_JOIN_MESSAGE)) { - event.setJoinMessage(null); - return; - } - - String customJoinMessage = settings.getProperty(RegistrationSettings.CUSTOM_JOIN_MESSAGE); - if (!customJoinMessage.isEmpty()) { - customJoinMessage = ChatColor.translateAlternateColorCodes('&', MiniMessageUtils.parseMiniMessageToLegacy(customJoinMessage)); - event.setJoinMessage(customJoinMessage - .replace("{PLAYERNAME}", player.getName()) - .replace("{DISPLAYNAME}", player.getDisplayName()) - .replace("{DISPLAYNAMENOCOLOR}", ChatColor.stripColor(player.getDisplayName())) - ); - } - - if (!settings.getProperty(RegistrationSettings.DELAY_JOIN_MESSAGE)) { - return; - } - - String name = player.getName().toLowerCase(Locale.ROOT); - String joinMsg = event.getJoinMessage(); - - // Remove the join message while the player isn't logging in - if (joinMsg != null) { - event.setJoinMessage(null); - joinMessageService.putMessage(name, joinMsg); - } - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - - // Note: quit message can be null, despite api documentation says not - if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) { - event.setQuitMessage(null); - } else if (settings.getProperty(RegistrationSettings.REMOVE_UNLOGGED_LEAVE_MESSAGE)) { - if (listenerService.shouldCancelEvent(event)) { - event.setQuitMessage(null); - } - } - - // Remove data from locale map when player quit - if (settings.getProperty(PluginSettings.I18N_MESSAGES)) { - I18NUtils.removeLocale(player.getUniqueId()); - } - - if (antiBotService.wasPlayerKicked(player.getName())) { - return; - } - - management.performQuit(player); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onPlayerKick(PlayerKickEvent event) { - // Note #831: Especially for offline CraftBukkit, we need to catch players being kicked because of - // "logged in from another location" and to cancel their kick - if (settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION) - && event.getReason().contains("You logged in from another location")) { - event.setCancelled(true); - return; - } - - final Player player = event.getPlayer(); - if (!antiBotService.wasPlayerKicked(player.getName())) { - management.performQuit(player); - } - } - - /* - * Chat/command events - */ - - private void removeUnauthorizedRecipients(AsyncPlayerChatEvent event) { - if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) { - event.getRecipients().removeIf(listenerService::shouldCancelEvent); - if (event.getRecipients().isEmpty()) { - event.setCancelled(true); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerChat(AsyncPlayerChatEvent event) { - if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) { - return; - } - - final Player player = event.getPlayer(); - final boolean mayPlayerSendChat = !listenerService.shouldCancelEvent(player) - || permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_CHAT_BEFORE_LOGIN); - if (mayPlayerSendChat) { - removeUnauthorizedRecipients(event); - } else { - event.setCancelled(true); - messages.send(player, MessageKey.DENIED_CHAT); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - String cmd = event.getMessage().split(" ")[0].toLowerCase(Locale.ROOT); - if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) { - return; - } - if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) { - return; - } - final Player player = event.getPlayer(); - if (!quickCommandsProtectionManager.isAllowed(player.getName())) { - event.setCancelled(true); - bukkitService.runTaskIfFolia(player, () -> player.kickPlayer(messages.retrieveSingle(player, MessageKey.QUICK_COMMAND_PROTECTION_KICK))); - // AuthMeReReloaded - Folia compatibility - return; - } - if (listenerService.shouldCancelEvent(player)) { - event.setCancelled(true); - messages.send(player, MessageKey.DENIED_COMMAND); - } - } - - /* - * Movement events - */ - - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onPlayerMove(PlayerMoveEvent event) { - if (settings.getProperty(ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(ALLOWED_MOVEMENT_RADIUS) <= 0) { - return; - } - - Location from = event.getFrom(); - Location to = event.getTo(); - if (to == null) { - return; - } - - /* - * Limit player X and Z movements - * Deny player Y+ movements (allows falling) - */ - - if (from.getX() == to.getX() - && from.getZ() == to.getZ() - && from.getY() - to.getY() >= 0) { - return; - } - - Player player = event.getPlayer(); - if (!listenerService.shouldCancelEvent(player)) { - return; - } - - if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) { - // "cancel" the event - event.setTo(event.getFrom()); - return; - } - - if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { - return; - } - - Location spawn = spawnLoader.getSpawnLocation(player); - if (spawn != null && spawn.getWorld() != null) { - if (!player.getWorld().equals(spawn.getWorld())) { - TeleportUtils.teleport(player,spawn); - } else if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) { - TeleportUtils.teleport(player,spawn); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onPlayerRespawn(PlayerRespawnEvent event) { - if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { - return; - } - if (!listenerService.shouldCancelEvent(event)) { - return; - } - Location spawn = spawnLoader.getSpawnLocation(event.getPlayer()); - if (spawn != null && spawn.getWorld() != null) { - event.setRespawnLocation(spawn); - } - } - - /* - * Entity/block interaction events - */ - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerInteract(PlayerInteractEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerHitPlayerEvent(EntityDamageByEntityEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerShear(PlayerShearEntityEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerFish(PlayerFishEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerBedEnter(PlayerBedEnterEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerEditBook(PlayerEditBookEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onSignChange(SignChangeEvent event) { - Player player = event.getPlayer(); - if (listenerService.shouldCancelEvent(player)) { - event.setCancelled(true); - } - } - - /* - * Inventory interactions - */ - -// @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) -// public void onPlayerPickupItem(EntityPickupItemEvent event) { -// if (listenerService.shouldCancelEvent(event)) { -// event.setCancelled(true); -// } -// } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerDropItem(PlayerDropItemEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerHeldItem(PlayerItemHeldEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - private boolean isInventoryOpenedByApi(Inventory inventory) { - if (inventory == null) { - return false; - } - if (PENDING_INVENTORIES.contains(inventory)) { - PENDING_INVENTORIES.remove(inventory); - return true; - } else { - return false; - } - } - @SuppressWarnings("all") - private boolean isInventoryWhitelisted(InventoryView inventory) { - if (inventory == null) { - return false; - } - Set whitelist = settings.getProperty(RestrictionSettings.UNRESTRICTED_INVENTORIES); - if (whitelist.isEmpty()) { - return false; - } - //append a string for String whitelist - String invName = ChatColor.stripColor(inventory.getTitle()).toLowerCase(Locale.ROOT); - if (settings.getProperty(RestrictionSettings.STRICT_UNRESTRICTED_INVENTORIES_CHECK)) { - return whitelist.contains(invName); - } - for (String wl : whitelist) { - if (invName.contains(wl)) { - return true; - } - } - return false; - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerInventoryOpen(InventoryOpenEvent event) { - final HumanEntity player = event.getPlayer(); - if (listenerService.shouldCancelEvent(player) - && !isInventoryWhitelisted(event.getView()) - && !isInventoryOpenedByApi(event.getInventory())) { - event.setCancelled(true); - - /* - * @note little hack cause InventoryOpenEvent cannot be cancelled for - * real, cause no packet is sent to server by client for the main inv - */ - bukkitService.scheduleSyncDelayedTask(player::closeInventory, 1); - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerInventoryClick(InventoryClickEvent event) { - if (listenerService.shouldCancelEvent(event.getWhoClicked()) - && !isInventoryWhitelisted(event.getView())) { - event.setCancelled(true); - } - } -// @EventHandler(priority = EventPriority.LOWEST) -// public void onSwitchHand(PlayerSwapHandItemsEvent event) { -// Player player = event.getPlayer(); -// if (!player.isSneaking() || !player.hasPermission("keybindings.use")) -// return; -// event.setCancelled(true); -// Bukkit.dispatchCommand(event.getPlayer(), "help"); -// } -} diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener111.java b/src/main/java/fr/xephi/authme/listener/PlayerListener111.java deleted file mode 100644 index 43b4ca33..00000000 --- a/src/main/java/fr/xephi/authme/listener/PlayerListener111.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityAirChangeEvent; - -import javax.inject.Inject; - -/** - * Listener of player events for events introduced in Minecraft 1.11. - */ -public class PlayerListener111 implements Listener { - - @Inject - private ListenerService listenerService; - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerAirChange(EntityAirChangeEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener19.java b/src/main/java/fr/xephi/authme/listener/PlayerListener19.java deleted file mode 100644 index aeb116dc..00000000 --- a/src/main/java/fr/xephi/authme/listener/PlayerListener19.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerSwapHandItemsEvent; - -import javax.inject.Inject; - -/** - * Listener of player events for events introduced in Minecraft 1.9. - */ -public class PlayerListener19 implements Listener { - - @Inject - private ListenerService listenerService; - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener19Spigot.java b/src/main/java/fr/xephi/authme/listener/PlayerListener19Spigot.java deleted file mode 100644 index a068f27d..00000000 --- a/src/main/java/fr/xephi/authme/listener/PlayerListener19Spigot.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.service.TeleportationService; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.spigotmc.event.player.PlayerSpawnLocationEvent; - -import javax.inject.Inject; - -public class PlayerListener19Spigot implements Listener { - - private static boolean isPlayerSpawnLocationEventCalled = false; - - @Inject - private TeleportationService teleportationService; - - - public static boolean isPlayerSpawnLocationEventCalled() { - return isPlayerSpawnLocationEventCalled; - } - - // Note: the following event is called since MC1.9, in older versions we have to fallback on the PlayerJoinEvent - @EventHandler(priority = EventPriority.HIGH) - public void onPlayerSpawn(PlayerSpawnLocationEvent event) { - isPlayerSpawnLocationEventCalled = true; - final Player player = event.getPlayer(); - - Location customSpawnLocation = teleportationService.prepareOnJoinSpawnLocation(player); - if (customSpawnLocation != null) { - event.setSpawnLocation(customSpawnLocation); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListenerHigherThan18.java b/src/main/java/fr/xephi/authme/listener/PlayerListenerHigherThan18.java deleted file mode 100644 index 66c408a1..00000000 --- a/src/main/java/fr/xephi/authme/listener/PlayerListenerHigherThan18.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityPickupItemEvent; -import org.bukkit.event.player.PlayerSwapHandItemsEvent; - -import javax.inject.Inject; - -public class PlayerListenerHigherThan18 implements Listener { - @Inject - private ListenerService listenerService; - - @Inject - private Settings settings; - - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerPickupItem(EntityPickupItemEvent event) { - if (listenerService.shouldCancelEvent(event)) { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onSwitchHand(PlayerSwapHandItemsEvent event) { - Player player = event.getPlayer(); - if (player.isSneaking() && player.hasPermission("keybindings.use") && settings.getProperty(PluginSettings.MENU_UNREGISTER_COMPATIBILITY)) { - event.setCancelled(true); - Bukkit.dispatchCommand(event.getPlayer(), "help"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/PurgeListener.java b/src/main/java/fr/xephi/authme/listener/PurgeListener.java deleted file mode 100644 index dcc3db4e..00000000 --- a/src/main/java/fr/xephi/authme/listener/PurgeListener.java +++ /dev/null @@ -1,89 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.api.v3.AuthMeApi; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; - -import javax.inject.Inject; -import java.io.File; -import java.util.UUID; - -public class PurgeListener implements Listener { - private final AuthMeApi authmeApi = AuthMeApi.getInstance(); - - @Inject - private Settings settings; - @Inject - private BukkitService bukkitService; - @Inject - private AuthMe plugin; - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - String name = player.getName(); - UUID playerUUID = event.getPlayer().getUniqueId(); - if (!authmeApi.isRegistered(name)) { - if (settings.getProperty(SecuritySettings.PURGE_DATA_ON_QUIT)) { - bukkitService.runTaskLater(() -> { - if (!player.isOnline()) { - deletePlayerData(playerUUID); - deletePlayerStats(playerUUID); - deleteAuthMePlayerData(playerUUID); - } - }, 100L); - } - } - } - - private void deletePlayerData(UUID playerUUID) { - // 获取服务器的存储文件夹路径 - File serverFolder = Bukkit.getServer().getWorldContainer(); - String worldFolderName = settings.getProperty(SecuritySettings.DELETE_PLAYER_DATA_WORLD); - // 构建playerdata文件夹路径 - File playerDataFolder = new File(serverFolder, File.separator + worldFolderName + File.separator + "playerdata"); - - // 构建玩家数据文件路径 - File playerDataFile = new File(playerDataFolder, File.separator + playerUUID + ".dat"); - File playerDataOldFile = new File(playerDataFolder, File.separator + playerUUID + ".dat_old"); - - // 删除玩家数据文件 - if (playerDataFile.exists()) { - playerDataFile.delete(); - } - if (playerDataOldFile.exists()) { - playerDataOldFile.delete(); - } - } - - private void deleteAuthMePlayerData(UUID playerUUID) { - File pluginFolder = plugin.getDataFolder(); - File path = new File(pluginFolder, File.separator + "playerdata" + File.separator + playerUUID); - File dataFile = new File(path, File.separator + "data.json"); - if (dataFile.exists()) { - dataFile.delete(); - path.delete(); - } - } - - private void deletePlayerStats(UUID playerUUID) { - // 获取服务器的存储文件夹路径 - File serverFolder = Bukkit.getServer().getWorldContainer(); - String worldFolderName = settings.getProperty(SecuritySettings.DELETE_PLAYER_DATA_WORLD); - // 构建stats文件夹路径 - File statsFolder = new File(serverFolder, File.separator + worldFolderName + File.separator + "stats"); - // 构建玩家统计数据文件路径 - File statsFile = new File(statsFolder, File.separator + playerUUID + ".json"); - // 删除玩家统计数据文件 - if (statsFile.exists()) { - statsFile.delete(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/ServerListener.java b/src/main/java/fr/xephi/authme/listener/ServerListener.java deleted file mode 100644 index 97cefa04..00000000 --- a/src/main/java/fr/xephi/authme/listener/ServerListener.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.xephi.authme.listener; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.listener.protocollib.ProtocolLibService; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.service.PluginHookService; -import fr.xephi.authme.settings.SpawnLoader; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.PluginEnableEvent; - -import javax.inject.Inject; - -/** - * Listener for server events. - */ -public class ServerListener implements Listener { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ServerListener.class); - - @Inject - private PluginHookService pluginHookService; - @Inject - private SpawnLoader spawnLoader; - @Inject - private ProtocolLibService protocolLibService; - @Inject - private PermissionsManager permissionsManager; - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPluginDisable(PluginDisableEvent event) { - final String pluginName = event.getPlugin().getName(); - - // Call the onPluginDisable method in the permissions manager - permissionsManager.onPluginDisable(pluginName); - - if ("Essentials".equalsIgnoreCase(pluginName)) { - pluginHookService.unhookEssentials(); - logger.info("Essentials has been disabled: unhooking"); - } else if ("CMI".equalsIgnoreCase(pluginName)) { - pluginHookService.unhookCmi(); - spawnLoader.unloadCmiSpawn(); - logger.info("CMI has been disabled: unhooking"); - } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { - pluginHookService.unhookMultiverse(); - logger.info("Multiverse-Core has been disabled: unhooking"); - } else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) { - spawnLoader.unloadEssentialsSpawn(); - logger.info("EssentialsSpawn has been disabled: unhooking"); - } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) { - protocolLibService.disable(); - logger.warning("ProtocolLib has been disabled, unhooking packet adapters!"); - } - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPluginEnable(PluginEnableEvent event) { - final String pluginName = event.getPlugin().getName(); - - // Call the onPluginEnable method in the permissions manager - permissionsManager.onPluginEnable(pluginName); - - if ("Essentials".equalsIgnoreCase(pluginName)) { - pluginHookService.tryHookToEssentials(); - } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { - pluginHookService.tryHookToMultiverse(); - } else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) { - spawnLoader.loadEssentialsSpawn(); - } else if ("CMI".equalsIgnoreCase(pluginName)) { - pluginHookService.tryHookToCmi(); - spawnLoader.loadCmiSpawn(); - } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) { - protocolLibService.setup(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/I18NGetLocalePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/I18NGetLocalePacketAdapter.java deleted file mode 100644 index 60148ba5..00000000 --- a/src/main/java/fr/xephi/authme/listener/protocollib/I18NGetLocalePacketAdapter.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.xephi.authme.listener.protocollib; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.ListenerPriority; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketEvent; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.util.message.I18NUtils; - -import java.util.UUID; - -class I18NGetLocalePacketAdapter extends PacketAdapter { - - I18NGetLocalePacketAdapter(AuthMe plugin) { - super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.SETTINGS); - } - - @Override - public void onPacketReceiving(PacketEvent event) { - if (event.getPacketType() == PacketType.Play.Client.SETTINGS) { - String locale = event.getPacket().getStrings().read(0).toLowerCase(); - UUID uuid = event.getPlayer().getUniqueId(); - - I18NUtils.addLocale(uuid, locale); - } - } - - public void register() { - ProtocolLibrary.getProtocolManager().addPacketListener(this); - } - - public void unregister() { - ProtocolLibrary.getProtocolManager().removePacketListener(this); - } -} diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java deleted file mode 100644 index c83b992b..00000000 --- a/src/main/java/fr/xephi/authme/listener/protocollib/InventoryPacketAdapter.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2015 AuthMe-Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package fr.xephi.authme.listener.protocollib; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.reflect.StructureModifier; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import java.util.Arrays; -import java.util.List; - -class InventoryPacketAdapter extends PacketAdapter { - - private static final int PLAYER_INVENTORY = 0; - // http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 hotbar, 45 off hand) - // +1 because an index starts with 0 - private static final int CRAFTING_SIZE = 5; - private static final int ARMOR_SIZE = 4; - private static final int MAIN_SIZE = 27; - private static final int HOTBAR_SIZE = 9; - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(InventoryPacketAdapter.class); - private final PlayerCache playerCache; - private final DataSource dataSource; - - InventoryPacketAdapter(AuthMe plugin, PlayerCache playerCache, DataSource dataSource) { - super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS); - this.playerCache = playerCache; - this.dataSource = dataSource; - } - - @Override - public void onPacketSending(PacketEvent packetEvent) { - Player player = packetEvent.getPlayer(); - PacketContainer packet = packetEvent.getPacket(); - - int windowId = packet.getIntegers().read(0); - if (windowId == PLAYER_INVENTORY && shouldHideInventory(player.getName())) { - packetEvent.setCancelled(true); - } - } - - /** - * Registers itself to ProtocolLib and blanks out the inventory packet to any applicable players. - * - * @param bukkitService the bukkit service (for retrieval of online players) - */ - public void register(BukkitService bukkitService) { - ProtocolLibrary.getProtocolManager().addPacketListener(this); - - bukkitService.getOnlinePlayers().stream() - .filter(player -> shouldHideInventory(player.getName())) - .forEach(this::sendBlankInventoryPacket); - } - - private boolean shouldHideInventory(String playerName) { - return !playerCache.isAuthenticated(playerName) && dataSource.isAuthAvailable(playerName); - } - - public void unregister() { - ProtocolLibrary.getProtocolManager().removePacketListener(this); - } - - /** - * Sends a blanked out packet to the given player in order to hide the inventory. - * - * @param player the player to send the blank inventory packet to - */ - public void sendBlankInventoryPacket(Player player) { - ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); - PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS); - inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY); - int inventorySize = CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE + HOTBAR_SIZE; - - ItemStack[] blankInventory = new ItemStack[inventorySize]; - Arrays.fill(blankInventory, new ItemStack(Material.AIR)); - - //old minecraft versions - StructureModifier itemArrayModifier = inventoryPacket.getItemArrayModifier(); - if (itemArrayModifier.size() > 0) { - itemArrayModifier.write(0, blankInventory); - } else { - //minecraft versions above 1.11 - StructureModifier> itemListModifier = inventoryPacket.getItemListModifier(); - itemListModifier.write(0, Arrays.asList(blankInventory)); - } - - protocolManager.sendServerPacket(player, inventoryPacket, false); - } -} diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java b/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java deleted file mode 100644 index f0297b33..00000000 --- a/src/main/java/fr/xephi/authme/listener/protocollib/ProtocolLibService.java +++ /dev/null @@ -1,159 +0,0 @@ -package fr.xephi.authme.listener.protocollib; - -import ch.jalu.injector.annotations.NoFieldScan; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.Utils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -@NoFieldScan -public class ProtocolLibService implements SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProtocolLibService.class); - - /* Packet Adapters */ - private InventoryPacketAdapter inventoryPacketAdapter; - private TabCompletePacketAdapter tabCompletePacketAdapter; - private I18NGetLocalePacketAdapter i18nGetLocalePacketAdapter; - - /* Settings */ - private boolean protectInvBeforeLogin; - private boolean denyTabCompleteBeforeLogin; - private boolean i18nMessagesSending; - - /* Service */ - private boolean isEnabled; - private final AuthMe plugin; - private final BukkitService bukkitService; - private final PlayerCache playerCache; - private final DataSource dataSource; - - @Inject - ProtocolLibService(AuthMe plugin, Settings settings, BukkitService bukkitService, PlayerCache playerCache, - DataSource dataSource) { - this.plugin = plugin; - this.bukkitService = bukkitService; - this.playerCache = playerCache; - this.dataSource = dataSource; - reload(settings); - } - - /** - * Set up the ProtocolLib packet adapters. - */ - public void setup() { - // Check if ProtocolLib is enabled on the server. - if (!plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib")) { - if (protectInvBeforeLogin) { - logger.warning("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); - } - - if (denyTabCompleteBeforeLogin) { - logger.warning("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it..."); - } - - if (i18nMessagesSending) { - logger.warning("WARNING! The i18n Messages feature requires ProtocolLib on lower version (< 1.15.2)! Disabling it..."); - } - - this.isEnabled = false; - return; - } - - // Set up packet adapters - if (protectInvBeforeLogin) { - if (inventoryPacketAdapter == null) { - // register the packet listener and start hiding it for all already online players (reload) - inventoryPacketAdapter = new InventoryPacketAdapter(plugin, playerCache, dataSource); - inventoryPacketAdapter.register(bukkitService); - } - } else if (inventoryPacketAdapter != null) { - inventoryPacketAdapter.unregister(); - inventoryPacketAdapter = null; - } - - if (denyTabCompleteBeforeLogin) { - if (tabCompletePacketAdapter == null) { - tabCompletePacketAdapter = new TabCompletePacketAdapter(plugin, playerCache); - tabCompletePacketAdapter.register(); - } - } else if (tabCompletePacketAdapter != null) { - tabCompletePacketAdapter.unregister(); - tabCompletePacketAdapter = null; - } - - if (i18nMessagesSending) { - if (i18nGetLocalePacketAdapter == null) { - i18nGetLocalePacketAdapter = new I18NGetLocalePacketAdapter(plugin); - i18nGetLocalePacketAdapter.register(); - } - } else if (i18nGetLocalePacketAdapter != null) { - i18nGetLocalePacketAdapter.unregister(); - i18nGetLocalePacketAdapter = null; - } - - this.isEnabled = true; - } - - /** - * Stops all features based on ProtocolLib. - */ - public void disable() { - isEnabled = false; - - if (inventoryPacketAdapter != null) { - inventoryPacketAdapter.unregister(); - inventoryPacketAdapter = null; - } - if (tabCompletePacketAdapter != null) { - tabCompletePacketAdapter.unregister(); - tabCompletePacketAdapter = null; - } - if (i18nGetLocalePacketAdapter != null) { - i18nGetLocalePacketAdapter.unregister(); - i18nGetLocalePacketAdapter = null; - } - } - - /** - * Send a packet to the player to give them a blank inventory. - * - * @param player The player to send the packet to. - */ - public void sendBlankInventoryPacket(Player player) { - if (isEnabled && inventoryPacketAdapter != null) { - inventoryPacketAdapter.sendBlankInventoryPacket(player); - } - } - - @Override - public void reload(Settings settings) { - boolean oldProtectInventory = this.protectInvBeforeLogin; - - this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN); - this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN); - this.i18nMessagesSending = settings.getProperty(PluginSettings.I18N_MESSAGES) && Utils.MAJOR_VERSION <= 15; - - //it was true and will be deactivated now, so we need to restore the inventory for every player - if (oldProtectInventory && !protectInvBeforeLogin && inventoryPacketAdapter != null) { - inventoryPacketAdapter.unregister(); - for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { - if (!playerCache.isAuthenticated(onlinePlayer.getName())) { - onlinePlayer.updateInventory(); - } - } - } - setup(); - } - -} diff --git a/src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java deleted file mode 100644 index 3f0bb316..00000000 --- a/src/main/java/fr/xephi/authme/listener/protocollib/TabCompletePacketAdapter.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.xephi.authme.listener.protocollib; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.ListenerPriority; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.reflect.FieldAccessException; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -class TabCompletePacketAdapter extends PacketAdapter { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TabCompletePacketAdapter.class); - private final PlayerCache playerCache; - - TabCompletePacketAdapter(AuthMe plugin, PlayerCache playerCache) { - super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE); - this.playerCache = playerCache; - } - - @Override - public void onPacketReceiving(PacketEvent event) { - if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) { - try { - if (!playerCache.isAuthenticated(event.getPlayer().getName())) { - event.setCancelled(true); - } - } catch (FieldAccessException e) { - logger.logException("Couldn't access field:", e); - } - } - } - - public void register() { - ProtocolLibrary.getProtocolManager().addPacketListener(this); - } - - public void unregister() { - ProtocolLibrary.getProtocolManager().removePacketListener(this); - } -} diff --git a/src/main/java/fr/xephi/authme/mail/EmailService.java b/src/main/java/fr/xephi/authme/mail/EmailService.java deleted file mode 100644 index 76968fb9..00000000 --- a/src/main/java/fr/xephi/authme/mail/EmailService.java +++ /dev/null @@ -1,223 +0,0 @@ -package fr.xephi.authme.mail; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.FileUtils; -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; - -import javax.activation.DataSource; -import javax.activation.FileDataSource; -import javax.imageio.ImageIO; -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; - -/** - * Creates emails and sends them. - */ -public class EmailService { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(EmailService.class); - - private final File dataFolder; - private final Settings settings; - private final SendMailSsl sendMailSsl; - - @Inject - EmailService(@DataFolder File dataFolder, Settings settings, SendMailSsl sendMailSsl) { - this.dataFolder = dataFolder; - this.settings = settings; - this.sendMailSsl = sendMailSsl; - } - - public boolean hasAllInformation() { - return sendMailSsl.hasAllInformation(); - } - - public boolean sendNewPasswordMail(String name, String mailAddress, String newPass,String ip,String time) { - HtmlEmail email; - try { - email = sendMailSsl.initializeMail(mailAddress); - } catch (EmailException e) { - logger.logException("Failed to create email with the given settings:", e); - return false; - } - - String mailText = replaceTagsForPasswordMail(settings.getNewPasswordEmailMessage(), name, newPass,ip,time); - File file = null; - if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) { - try { - file = generatePasswordImage(name, newPass); - mailText = embedImageIntoEmailContent(file, email, mailText); - } catch (IOException | EmailException e) { - logger.logException( - "Unable to send new password as image for email " + mailAddress + ":", e); - } - } - - boolean couldSendEmail = sendMailSsl.sendEmail(mailText, email); - FileUtils.delete(file); - return couldSendEmail; - } - - /** - * Sends an email to the user with his new password. - * - * @param name the name of the player - * @param mailAddress the player's email - * @param newPass the new password - * @return true if email could be sent, false otherwise - */ - public boolean sendPasswordMail(String name, String mailAddress, String newPass, String time) { - if (!hasAllInformation()) { - logger.warning("Cannot perform email registration: not all email settings are complete"); - return false; - } - - HtmlEmail email; - try { - email = sendMailSsl.initializeMail(mailAddress); - } catch (EmailException e) { - logger.logException("Failed to create email with the given settings:", e); - return false; - } - - String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass,time); - // Generate an image? - File file = null; - if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) { - try { - file = generatePasswordImage(name, newPass); - mailText = embedImageIntoEmailContent(file, email, mailText); - } catch (IOException | EmailException e) { - logger.logException( - "Unable to send new password as image for email " + mailAddress + ":", e); - } - } - - boolean couldSendEmail = sendMailSsl.sendEmail(mailText, email); - FileUtils.delete(file); - return couldSendEmail; - } - /** - * Sends an email to the user with the temporary verification code. - * - * @param name the name of the player - * @param mailAddress the player's email - * @param code the verification code - */ - public void sendVerificationMail(String name, String mailAddress, String code, String time) { - if (!hasAllInformation()) { - logger.warning("Cannot send verification email: not all email settings are complete"); - return; - } - - HtmlEmail email; - try { - email = sendMailSsl.initializeMail(mailAddress); - } catch (EmailException e) { - logger.logException("Failed to create verification email with the given settings:", e); - return; - } - - String mailText = replaceTagsForVerificationEmail(settings.getVerificationEmailMessage(), name, code, - settings.getProperty(SecuritySettings.VERIFICATION_CODE_EXPIRATION_MINUTES),time); - sendMailSsl.sendEmail(mailText, email); - } - - /** - * Sends an email to the user with a recovery code for the password recovery process. - * - * @param name the name of the player - * @param email the player's email address - * @param code the recovery code - * @return true if email could be sent, false otherwise - */ - public boolean sendRecoveryCode(String name, String email, String code, String time) { - HtmlEmail htmlEmail; - try { - htmlEmail = sendMailSsl.initializeMail(email); - } catch (EmailException e) { - logger.logException("Failed to create email for recovery code:", e); - return false; - } - - String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(), - name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID),time); - return sendMailSsl.sendEmail(message, htmlEmail); - } - - public void sendShutDown(String email, String time) { - HtmlEmail htmlEmail; - try { - htmlEmail = sendMailSsl.initializeMail(email); - } catch (EmailException e) { - logger.logException("Failed to create email for shutdown:", e); - return; - } - - String message = replaceTagsForShutDownMail(settings.getShutdownEmailMessage(), time); - sendMailSsl.sendEmail(message, htmlEmail); - } - - private File generatePasswordImage(String name, String newPass) throws IOException { - ImageGenerator gen = new ImageGenerator(newPass); - File file = new File(dataFolder, name + "_new_pass.jpg"); - ImageIO.write(gen.generateImage(), "jpg", file); - return file; - } - - private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content) - throws EmailException { - DataSource source = new FileDataSource(image); - String tag = email.embed(source, image.getName()); - return content.replace("", ""); - } - - private String replaceTagsForPasswordMail(String mailText, String name, String newPass,String ip,String time) { - return mailText - .replace("", name) - .replace("", settings.getProperty(PluginSettings.SERVER_NAME)) - .replace("", newPass) - .replace("", ip) - .replace("

- * Only the "XOAUTH2" mechanism is supported. The {@code callbackHandler} is - * passed to the OAuth2SaslClient. Other parameters are ignored. - */ -public class OAuth2SaslClientFactory implements SaslClientFactory { - - private static final Logger logger = Logger.getLogger(OAuth2SaslClientFactory.class.getName()); - - public static final String OAUTH_TOKEN_PROP = "mail.smpt.sasl.mechanisms.oauth2.oauthToken"; - - public SaslClient createSaslClient(String[] mechanisms, - String authorizationId, String protocol, String serverName, - Map props, CallbackHandler callbackHandler) { - boolean matchedMechanism = false; - for (int i = 0; i < mechanisms.length; ++i) { - if ("XOAUTH2".equalsIgnoreCase(mechanisms[i])) { - matchedMechanism = true; - break; - } - } - if (!matchedMechanism) { - logger.info("Failed to match any mechanisms"); - return null; - } - return new OAuth2SaslClient((String) props.get(OAUTH_TOKEN_PROP), callbackHandler); - } - - public String[] getMechanismNames(Map props) { - return new String[] { "XOAUTH2" }; - } -} diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSsl.java b/src/main/java/fr/xephi/authme/mail/SendMailSsl.java deleted file mode 100644 index b7e9fd41..00000000 --- a/src/main/java/fr/xephi/authme/mail/SendMailSsl.java +++ /dev/null @@ -1,158 +0,0 @@ -package fr.xephi.authme.mail; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.output.LogLevel; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.StringUtils; -import org.apache.commons.mail.EmailConstants; -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; - -import javax.activation.CommandMap; -import javax.activation.MailcapCommandMap; -import javax.inject.Inject; -import javax.mail.Session; -import java.security.Security; -import java.util.Properties; - -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; -import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; - - -/** - * Sends emails to players on behalf of the server. - */ -public class SendMailSsl { - - private ConsoleLogger logger = ConsoleLoggerFactory.get(SendMailSsl.class); - - @Inject - private Settings settings; - - /** - * Returns whether all necessary settings are set for sending mails. - * - * @return true if the necessary email settings are set, false otherwise - */ - public boolean hasAllInformation() { - return !settings.getProperty(MAIL_ACCOUNT).isEmpty() - && !settings.getProperty(MAIL_PASSWORD).isEmpty(); - } - - /** - * Creates a {@link HtmlEmail} object configured as per the AuthMe config - * with the given email address as recipient. - * - * @param emailAddress the email address the email is destined for - * @return the created HtmlEmail object - * @throws EmailException if the mail is invalid - */ - public HtmlEmail initializeMail(String emailAddress) throws EmailException { - String senderMail = StringUtils.isBlank(settings.getProperty(EmailSettings.MAIL_ADDRESS)) - ? settings.getProperty(EmailSettings.MAIL_ACCOUNT) - : settings.getProperty(EmailSettings.MAIL_ADDRESS); - - String senderName = StringUtils.isBlank(settings.getProperty(EmailSettings.MAIL_SENDER_NAME)) - ? senderMail - : settings.getProperty(EmailSettings.MAIL_SENDER_NAME); - String mailPassword = settings.getProperty(EmailSettings.MAIL_PASSWORD); - int port = settings.getProperty(EmailSettings.SMTP_PORT); - - HtmlEmail email = new HtmlEmail(); - email.setCharset(EmailConstants.UTF_8); - email.setSmtpPort(port); - email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST)); - email.addTo(emailAddress); - email.setFrom(senderMail, senderName); - email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT)); - email.setAuthentication(settings.getProperty(EmailSettings.MAIL_ACCOUNT), mailPassword); - if (settings.getProperty(PluginSettings.LOG_LEVEL).includes(LogLevel.DEBUG)) { - email.setDebug(true); - } - - setPropertiesForPort(email, port); - return email; - } - - /** - * Sets the given content to the HtmlEmail object and sends it. - * - * @param content the content to set - * @param email the email object to send - * @return true upon success, false otherwise - */ - public boolean sendEmail(String content, HtmlEmail email) { - Thread.currentThread().setContextClassLoader(SendMailSsl.class.getClassLoader()); - // Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative - // cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type - MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); - mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); - mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); - mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); - mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); - mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); - - try { - email.setHtmlMsg(content); - email.setTextMsg(content); - } catch (EmailException e) { - logger.logException("Your email.html config contains an error and cannot be sent:", e); - return false; - } - try { - email.send(); - return true; - } catch (EmailException e) { - logger.logException("Failed to send a mail to " + email.getToAddresses() + ":", e); - return false; - } - } - - /** - * Sets properties to the given HtmlEmail object based on the port from which it will be sent. - * - * @param email the email object to configure - * @param port the configured outgoing port - */ - private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException { - switch (port) { - case 587: - String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN); - if (!oAuth2Token.isEmpty()) { - if (Security.getProvider("Google OAuth2 Provider") == null) { - Security.addProvider(new OAuth2Provider()); - } - Properties mailProperties = email.getMailSession().getProperties(); - mailProperties.setProperty("mail.smtp.ssl.enable", "true"); - mailProperties.setProperty("mail.smtp.auth.mechanisms", "XOAUTH2"); - mailProperties.setProperty("mail.smtp.sasl.enable", "true"); - mailProperties.setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2"); - mailProperties.setProperty("mail.smtp.auth.login.disable", "true"); - mailProperties.setProperty("mail.smtp.auth.plain.disable", "true"); - mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oAuth2Token); - email.setMailSession(Session.getInstance(mailProperties)); - } else { - email.setStartTLSEnabled(true); - email.setStartTLSRequired(true); - } - break; - case 25: - if (settings.getProperty(EmailSettings.PORT25_USE_TLS)) { - email.setStartTLSEnabled(true); - email.setSSLCheckServerIdentity(true); - } - break; - case 465: - email.setSslSmtpPort(Integer.toString(port)); - email.setSSLOnConnect(true); - break; - default: - email.setStartTLSEnabled(true); - email.setSSLOnConnect(true); - email.setSSLCheckServerIdentity(true); - } - } -} diff --git a/src/main/java/fr/xephi/authme/message/AbstractMessageFileHandler.java b/src/main/java/fr/xephi/authme/message/AbstractMessageFileHandler.java deleted file mode 100644 index bdc9f0f2..00000000 --- a/src/main/java/fr/xephi/authme/message/AbstractMessageFileHandler.java +++ /dev/null @@ -1,170 +0,0 @@ -package fr.xephi.authme.message; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.FileUtils; -import fr.xephi.authme.util.message.I18NUtils; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.File; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static fr.xephi.authme.message.MessagePathHelper.DEFAULT_LANGUAGE; - -/** - * Handles a YAML message file with a default file fallback. - */ -public abstract class AbstractMessageFileHandler implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AbstractMessageFileHandler.class); - - @DataFolder - @Inject - private File dataFolder; - - @Inject - private Settings settings; - - private String filename; - private FileConfiguration configuration; - private Map i18nConfiguration; - private final String defaultFile; - - protected AbstractMessageFileHandler() { - this.defaultFile = createFilePath(DEFAULT_LANGUAGE); - } - - @Override - @PostConstruct - public void reload() { - String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); - filename = createFilePath(language); - File messagesFile = initializeFile(filename); - configuration = YamlConfiguration.loadConfiguration(messagesFile); - i18nConfiguration = null; - } - - protected String getLanguage() { - return settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); - } - - protected File getUserLanguageFile() { - return new File(dataFolder, filename); - } - - protected String getFilename() { - return filename; - } - - /** - * Returns whether the message file configuration has an entry at the given path. - * - * @param path the path to verify - * @return true if an entry exists for the path in the messages file, false otherwise - */ - public boolean hasSection(String path) { - return configuration.get(path) != null; - } - - /** - * Returns the message for the given key. - * - * @param key the key to retrieve the message for - * @return the message - */ - public String getMessage(String key) { - String message = configuration.getString(key); - return message == null - ? "Error retrieving message '" + key + "'" - : message; - } - - /** - * Returns the i18n message for the given key and given locale. - * - * @param key the key to retrieve the message for - * @param locale the locale that player client setting uses - * @return the message - */ - public String getMessageByLocale(String key, String locale) { - if (locale == null || !settings.getProperty(PluginSettings.I18N_MESSAGES)) { - return getMessage(key); - } - - String message = getI18nConfiguration(locale).getString(key); - return message == null - ? "Error retrieving message '" + key + "'" - : message; - } - - /** - * Returns the message for the given key only if it exists, - * i.e. without falling back to the default file. - * - * @param key the key to retrieve the message for - * @return the message, or {@code null} if not available - */ - public String getMessageIfExists(String key) { - return configuration.getString(key); - } - - public FileConfiguration getI18nConfiguration(String locale) { - if (i18nConfiguration == null) { - i18nConfiguration = new ConcurrentHashMap<>(); - } - - locale = I18NUtils.localeToCode(locale, settings); - - if (i18nConfiguration.containsKey(locale)) { - return i18nConfiguration.get(locale); - } else { - // Sync with reload(); - String i18nFilename = createFilePath(locale); - File i18nMessagesFile = initializeFile(i18nFilename); - FileConfiguration config = YamlConfiguration.loadConfiguration(i18nMessagesFile); - - i18nConfiguration.put(locale, config); - - return config; - } - } - - /** - * Creates the path to the messages file for the given language code. - * - * @param language the language code - * @return path to the message file for the given language - */ - protected abstract String createFilePath(String language); - - /** - * Copies the messages file from the JAR to the local messages/ folder if it doesn't exist. - * - * @param filePath path to the messages file to use - * @return the messages file to use - */ - @VisibleForTesting - File initializeFile(String filePath) { - File file = new File(dataFolder, filePath); - // Check that JAR file exists to avoid logging an error - if (FileUtils.getResourceFromJar(filePath) != null && FileUtils.copyFileFromResource(file, filePath)) { - return file; - } - - if (FileUtils.copyFileFromResource(file, defaultFile)) { - return file; - } else { - logger.warning("Wanted to copy default messages file '" + defaultFile + "' from JAR but it didn't exist"); - return null; - } - } -} diff --git a/src/main/java/fr/xephi/authme/message/HelpMessagesFileHandler.java b/src/main/java/fr/xephi/authme/message/HelpMessagesFileHandler.java deleted file mode 100644 index 89dc5224..00000000 --- a/src/main/java/fr/xephi/authme/message/HelpMessagesFileHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.message; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.util.FileUtils; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import javax.inject.Inject; -import java.io.InputStream; -import java.io.InputStreamReader; - -import static fr.xephi.authme.message.MessagePathHelper.DEFAULT_LANGUAGE; - -/** - * File handler for the help_xx.yml resource. - */ -public class HelpMessagesFileHandler extends AbstractMessageFileHandler { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(HelpMessagesFileHandler.class); - - private FileConfiguration defaultConfiguration; - - @Inject // Trigger injection in the superclass - HelpMessagesFileHandler() { - } - - /** - * Returns the message for the given key. - * - * @param key the key to retrieve the message for - * @return the message - */ - @Override - public String getMessage(String key) { - String message = getMessageIfExists(key); - - if (message == null) { - logger.warning("Error getting message with key '" + key + "'. " - + "Please update your config file '" + getFilename() + "' or run /authme messages help"); - return getDefault(key); - } - return message; - } - - /** - * Gets the message from the default file. - * - * @param key the key to retrieve the message for - * @return the message from the default file - */ - private String getDefault(String key) { - if (defaultConfiguration == null) { - InputStream stream = FileUtils.getResourceFromJar(createFilePath(DEFAULT_LANGUAGE)); - defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream)); - } - String message = defaultConfiguration.getString(key); - return message == null - ? "Error retrieving message '" + key + "'" - : message; - } - - @Override - protected String createFilePath(String language) { - return MessagePathHelper.createHelpMessageFilePath(language); - } -} diff --git a/src/main/java/fr/xephi/authme/message/MessageKey.java b/src/main/java/fr/xephi/authme/message/MessageKey.java deleted file mode 100644 index ab05738d..00000000 --- a/src/main/java/fr/xephi/authme/message/MessageKey.java +++ /dev/null @@ -1,399 +0,0 @@ -package fr.xephi.authme.message; - -/** - * Keys for translatable messages managed by {@link Messages}. - */ -public enum MessageKey { - /** - * You have been disconnected due to doubled login. - */ - DOUBLE_LOGIN_FIX("double_login_fix.fix_message"), - - /** - * You are stuck in portal during Login. - */ - LOCATION_FIX_PORTAL("login_location_fix.fix_portal"), - - /** - * You are stuck underground during Login. - */ - LOCATION_FIX_UNDERGROUND("login_location_fix.fix_underground"), - - /** - * You are stuck underground during Login, but we cant fix it. - */ - LOCATION_FIX_UNDERGROUND_CANT_FIX("login_location_fix.cannot_fix_underground"), - - /** - * Bedrock auto login success! - */ - BEDROCK_AUTO_LOGGED_IN("bedrock_auto_login.success"), - - /** - * In order to use this command you must be authenticated! - */ - DENIED_COMMAND("error.denied_command"), - - /** - * A player with the same IP is already in game! - */ - SAME_IP_ONLINE("on_join_validation.same_ip_online"), - - /** - * In order to chat you must be authenticated! - */ - DENIED_CHAT("error.denied_chat"), - - /** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */ - KICK_ANTIBOT("antibot.kick_antibot"), - - /** This user isn't registered! */ - UNKNOWN_USER("error.unregistered_user"), - - /** You're not logged in! */ - NOT_LOGGED_IN("error.not_logged_in"), - - /** Usage: /login <password> */ - USAGE_LOGIN("login.command_usage"), - - /** Wrong password! */ - WRONG_PASSWORD("login.wrong_password"), - - /** Successfully unregistered! */ - UNREGISTERED_SUCCESS("unregister.success"), - - /** In-game registration is disabled! */ - REGISTRATION_DISABLED("registration.disabled"), - - /** Logged-in due to Session Reconnection. */ - SESSION_RECONNECTION("session.valid_session"), - - /** Successful login! */ - LOGIN_SUCCESS("login.success"), - - /** Your account isn't activated yet, please check your emails! */ - ACCOUNT_NOT_ACTIVATED("misc.account_not_activated"), - - /** You already have registered this username! */ - NAME_ALREADY_REGISTERED("registration.name_taken"), - - /** You don't have the permission to perform this action! */ - NO_PERMISSION("error.no_permission"), - - /** An unexpected error occurred, please contact an administrator! */ - ERROR("error.unexpected_error"), - - /** Please, login with the command: /login <password> */ - LOGIN_MESSAGE("login.login_request"), - - /** Please, register to the server with the command: /register <password> <ConfirmPassword> */ - REGISTER_MESSAGE("registration.register_request"), - - /** You have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection! */ - MAX_REGISTER_EXCEEDED("error.max_registration", "%max_acc", "%reg_count", "%reg_names"), - - /** Usage: /register <password> <ConfirmPassword> */ - USAGE_REGISTER("registration.command_usage"), - - /** Usage: /unregister <password> */ - USAGE_UNREGISTER("unregister.command_usage"), - - /** Password changed successfully! */ - PASSWORD_CHANGED_SUCCESS("misc.password_changed"), - - /** Passwords didn't match, check them again! */ - PASSWORD_MATCH_ERROR("password.match_error"), - - /** You can't use your name as password, please choose another one... */ - PASSWORD_IS_USERNAME_ERROR("password.name_in_password"), - - /** The chosen password isn't safe, please choose another one... */ - PASSWORD_UNSAFE_ERROR("password.unsafe_password"), - - /** Your chosen password is not secure. It was used %pwned_count times already! Please use a stronger password... */ - PASSWORD_PWNED_ERROR("password.pwned_password", "%pwned_count"), - - /** Your password contains illegal characters. Allowed chars: %valid_chars */ - PASSWORD_CHARACTERS_ERROR("password.forbidden_characters", "%valid_chars"), - - /** Your IP has been changed and your session data has expired! */ - SESSION_EXPIRED("session.invalid_session"), - - /** Only registered users can join the server! Please visit http://example.com to register yourself! */ - MUST_REGISTER_MESSAGE("registration.reg_only"), - - /** You're already logged in! */ - ALREADY_LOGGED_IN_ERROR("error.logged_in"), - - /** Logged out successfully! */ - LOGOUT_SUCCESS("misc.logout"), - - /** The same username is already playing on the server! */ - USERNAME_ALREADY_ONLINE_ERROR("on_join_validation.same_nick_online"), - - /** Successfully registered! */ - REGISTER_SUCCESS("registration.success"), - - /** Your password is too short or too long! Please try with another one! */ - INVALID_PASSWORD_LENGTH("password.wrong_length"), - - /** Configuration and database have been reloaded correctly! */ - CONFIG_RELOAD_SUCCESS("misc.reload"), - - /** Login timeout exceeded, you have been kicked from the server, please try again! */ - LOGIN_TIMEOUT_ERROR("login.timeout_error"), - - /** Usage: /changepassword <oldPassword> <newPassword> */ - USAGE_CHANGE_PASSWORD("misc.usage_change_password"), - - /** Your username is either too short or too long! */ - INVALID_NAME_LENGTH("on_join_validation.name_length"), - - /** Your username contains illegal characters. Allowed chars: %valid_chars */ - INVALID_NAME_CHARACTERS("on_join_validation.characters_in_name", "%valid_chars"), - - /** Please add your email to your account with the command: /email add <yourEmail> <confirmEmail> */ - ADD_EMAIL_MESSAGE("email.add_email_request"), - - /** Forgot your password? Please use the command: /email recovery <yourEmail> */ - FORGOT_PASSWORD_MESSAGE("recovery.forgot_password_hint"), - - /** To log in you have to solve a captcha code, please use the command: /captcha %captcha_code */ - USAGE_CAPTCHA("captcha.usage_captcha", "%captcha_code"), - - /** Wrong captcha, please type "/captcha %captcha_code" into the chat! */ - CAPTCHA_WRONG_ERROR("captcha.wrong_captcha", "%captcha_code"), - - /** Captcha code solved correctly! */ - CAPTCHA_SUCCESS("captcha.valid_captcha"), - - /** To register you have to solve a captcha first, please use the command: /captcha %captcha_code */ - CAPTCHA_FOR_REGISTRATION_REQUIRED("captcha.captcha_for_registration", "%captcha_code"), - - /** Valid captcha! You may now register with /register */ - REGISTER_CAPTCHA_SUCCESS("captcha.register_captcha_valid"), - - /** A VIP player has joined the server when it was full! */ - KICK_FOR_VIP("error.kick_for_vip"), - - /** The server is full, try again later! */ - KICK_FULL_SERVER("on_join_validation.kick_full_server"), - - /** An error occurred: unresolved player hostname! **/ - KICK_UNRESOLVED_HOSTNAME("error.kick_unresolved_hostname"), - - /** Usage: /email add <email> <confirmEmail> */ - USAGE_ADD_EMAIL("email.usage_email_add"), - - /** Usage: /email change <oldEmail> <newEmail> */ - USAGE_CHANGE_EMAIL("email.usage_email_change"), - - /** Usage: /email recovery <Email> */ - USAGE_RECOVER_EMAIL("recovery.command_usage"), - - /** Invalid new email, try again! */ - INVALID_NEW_EMAIL("email.new_email_invalid"), - - /** Invalid old email, try again! */ - INVALID_OLD_EMAIL("email.old_email_invalid"), - - /** Invalid email address, try again! */ - INVALID_EMAIL("email.invalid"), - - /** Email address successfully added to your account! */ - EMAIL_ADDED_SUCCESS("email.added"), - - /** Adding email was not allowed */ - EMAIL_ADD_NOT_ALLOWED("email.add_not_allowed"), - - /** Please confirm your email address! */ - CONFIRM_EMAIL_MESSAGE("email.request_confirmation"), - - /** Email address changed correctly! */ - EMAIL_CHANGED_SUCCESS("email.changed"), - - /** Changing email was not allowed */ - EMAIL_CHANGE_NOT_ALLOWED("email.change_not_allowed"), - - /** Your current email address is: %email */ - EMAIL_SHOW("email.email_show", "%email"), - - /** You currently don't have email address associated with this account. */ - SHOW_NO_EMAIL("email.no_email_for_account"), - - /** Recovery email sent successfully! Please check your email inbox! */ - RECOVERY_EMAIL_SENT_MESSAGE("recovery.email_sent"), - - /** Your country is banned from this server! */ - COUNTRY_BANNED_ERROR("on_join_validation.country_banned"), - - /** [AntiBotService] AntiBot enabled due to the huge number of connections! */ - ANTIBOT_AUTO_ENABLED_MESSAGE("antibot.auto_enabled"), - - /** [AntiBotService] AntiBot disabled after %m minutes! */ - ANTIBOT_AUTO_DISABLED_MESSAGE("antibot.auto_disabled", "%m"), - - /** The email address is already being used */ - EMAIL_ALREADY_USED_ERROR("email.already_used"), - - /** Your secret code is %code. You can scan it from here %url */ - TWO_FACTOR_CREATE("two_factor.code_created", "%code", "%url"), - - /** Please confirm your code with /2fa confirm <code> */ - TWO_FACTOR_CREATE_CONFIRMATION_REQUIRED("two_factor.confirmation_required"), - - /** Please submit your two-factor authentication code with /2fa code <code> */ - TWO_FACTOR_CODE_REQUIRED("two_factor.code_required"), - - /** Two-factor authentication is already enabled for your account! */ - TWO_FACTOR_ALREADY_ENABLED("two_factor.already_enabled"), - - /** No 2fa key has been generated for you or it has expired. Please run /2fa add */ - TWO_FACTOR_ENABLE_ERROR_NO_CODE("two_factor.enable_error_no_code"), - - /** Successfully enabled two-factor authentication for your account */ - TWO_FACTOR_ENABLE_SUCCESS("two_factor.enable_success"), - - /** Wrong code or code has expired. Please run /2fa add */ - TWO_FACTOR_ENABLE_ERROR_WRONG_CODE("two_factor.enable_error_wrong_code"), - - /** Two-factor authentication is not enabled for your account. Run /2fa add */ - TWO_FACTOR_NOT_ENABLED_ERROR("two_factor.not_enabled_error"), - - /** Successfully removed two-factor auth from your account */ - TWO_FACTOR_REMOVED_SUCCESS("two_factor.removed_success"), - - /** Invalid code! */ - TWO_FACTOR_INVALID_CODE("two_factor.invalid_code"), - - /** You are not the owner of this account. Please choose another name! */ - NOT_OWNER_ERROR("on_join_validation.not_owner_error"), - - /** You should join using username %valid, not %invalid. */ - INVALID_NAME_CASE("on_join_validation.invalid_name_case", "%valid", "%invalid"), - - /** You have been temporarily banned for failing to log in too many times. */ - TEMPBAN_MAX_LOGINS("error.tempban_max_logins"), - - /** You own %count accounts: */ - ACCOUNTS_OWNED_SELF("misc.accounts_owned_self", "%count"), - - /** The player %name has %count accounts: */ - ACCOUNTS_OWNED_OTHER("misc.accounts_owned_other", "%name", "%count"), - - /** An admin just registered you; please log in again */ - KICK_FOR_ADMIN_REGISTER("registration.kicked_admin_registered"), - - /** Error: not all required settings are set for sending emails. Please contact an admin. */ - INCOMPLETE_EMAIL_SETTINGS("email.incomplete_settings"), - - /** The email could not be sent. Please contact an administrator. */ - EMAIL_SEND_FAILURE("email.send_failure"), - - /** A recovery code to reset your password has been sent to your email. */ - RECOVERY_CODE_SENT("recovery.code.code_sent"), - - /** The recovery code is not correct! You have %count tries remaining. */ - INCORRECT_RECOVERY_CODE("recovery.code.incorrect", "%count"), - - /** - * You have exceeded the maximum number of attempts to enter the recovery code. - * Use "/email recovery [email]" to generate a new one. - */ - RECOVERY_TRIES_EXCEEDED("recovery.code.tries_exceeded"), - - /** Recovery code entered correctly! */ - RECOVERY_CODE_CORRECT("recovery.code.correct"), - - /** Please use the command /email setpassword to change your password immediately. */ - RECOVERY_CHANGE_PASSWORD("recovery.code.change_password"), - - /** You cannot change your password using this command anymore. */ - CHANGE_PASSWORD_EXPIRED("email.change_password_expired"), - - /** An email was already sent recently. You must wait %time before you can send a new one. */ - EMAIL_COOLDOWN_ERROR("email.email_cooldown_error", "%time"), - - /** - * This command is sensitive and requires an email verification! - * Check your inbox and follow the email's instructions. - */ - VERIFICATION_CODE_REQUIRED("verification.code_required"), - - /** Usage: /verification <code> */ - USAGE_VERIFICATION_CODE("verification.command_usage"), - - /** Incorrect code, please type "/verification <code>" into the chat, using the code you received by email */ - INCORRECT_VERIFICATION_CODE("verification.incorrect_code"), - - /** Your identity has been verified! You can now execute all commands within the current session! */ - VERIFICATION_CODE_VERIFIED("verification.success"), - - /** You can already execute every sensitive command within the current session! */ - VERIFICATION_CODE_ALREADY_VERIFIED("verification.already_verified"), - - /** Your code has expired! Execute another sensitive command to get a new code! */ - VERIFICATION_CODE_EXPIRED("verification.code_expired"), - - /** To verify your identity you need to link an email address with your account! */ - VERIFICATION_CODE_EMAIL_NEEDED("verification.email_needed"), - - /** You used a command too fast! Please, join the server again and wait more before using any command. */ - QUICK_COMMAND_PROTECTION_KICK("on_join_validation.quick_command"), - - /** second */ - SECOND("time.second"), - - /** seconds */ - SECONDS("time.seconds"), - - /** minute */ - MINUTE("time.minute"), - - /** minutes */ - MINUTES("time.minutes"), - - /** hour */ - HOUR("time.hour"), - - /** hours */ - HOURS("time.hours"), - - /** day */ - DAY("time.day"), - - /** days */ - DAYS("time.days"); - - - private String key; - private String[] tags; - - MessageKey(String key, String... tags) { - this.key = key; - this.tags = tags; - } - - /** - * Return the key used in the messages file. - * - * @return The key - */ - public String getKey() { - return key; - } - - /** - * Return a list of tags (texts) that are replaced with actual content in AuthMe. - * - * @return List of tags - */ - public String[] getTags() { - return tags; - } - - @Override - public String toString() { - return key; - } -} diff --git a/src/main/java/fr/xephi/authme/message/MessagePathHelper.java b/src/main/java/fr/xephi/authme/message/MessagePathHelper.java deleted file mode 100644 index 82c829d1..00000000 --- a/src/main/java/fr/xephi/authme/message/MessagePathHelper.java +++ /dev/null @@ -1,77 +0,0 @@ -package fr.xephi.authme.message; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Helper for creating and processing paths to message files. - */ -public final class MessagePathHelper { - - /** The default language (used as fallback, assumed to be complete, etc.). */ - public static final String DEFAULT_LANGUAGE = "en"; - /** Local path to the folder containing the message files. */ - public static final String MESSAGES_FOLDER = "messages/"; - /** Local path to the default messages file (messages/messages_en.yml). */ - public static final String DEFAULT_MESSAGES_FILE = createMessageFilePath(DEFAULT_LANGUAGE); - - private static final Pattern MESSAGE_FILE_PATTERN = Pattern.compile("messages_([a-z]+)\\.yml"); - private static final Pattern HELP_MESSAGES_FILE = Pattern.compile("help_[a-z]+\\.yml"); - - private MessagePathHelper() { - } - - /** - * Creates the local path to the messages file for the provided language code. - * - * @param languageCode the language code - * @return local path to the messages file of the given language - */ - public static String createMessageFilePath(String languageCode) { - return "messages/messages_" + languageCode + ".yml"; - } - - /** - * Creates the local path to the help messages file for the provided language code. - * - * @param languageCode the language code - * @return local path to the help messages file of the given language - */ - public static String createHelpMessageFilePath(String languageCode) { - return "messages/help_" + languageCode + ".yml"; - } - - /** - * Returns whether the given file name is a messages file. - * - * @param filename the file name to test - * @return true if it is a messages file, false otherwise - */ - public static boolean isMessagesFile(String filename) { - return MESSAGE_FILE_PATTERN.matcher(filename).matches(); - } - - /** - * Returns the language code the given file name is for if it is a messages file, otherwise null is returned. - * - * @param filename the file name to process - * @return the language code the file name is a messages file for, or null if not applicable - */ - public static String getLanguageIfIsMessagesFile(String filename) { - Matcher matcher = MESSAGE_FILE_PATTERN.matcher(filename); - if (matcher.matches()) { - return matcher.group(1); - } - return null; - } - - /** - * Returns whether the given file name is a help messages file. - * - * @param filename the file name to test - * @return true if it is a help messages file, false otherwise - */ - public static boolean isHelpFile(String filename) { - return HELP_MESSAGES_FILE.matcher(filename).matches(); - } -} diff --git a/src/main/java/fr/xephi/authme/message/Messages.java b/src/main/java/fr/xephi/authme/message/Messages.java deleted file mode 100644 index 0d7ec317..00000000 --- a/src/main/java/fr/xephi/authme/message/Messages.java +++ /dev/null @@ -1,201 +0,0 @@ -package fr.xephi.authme.message; - -import com.google.common.collect.ImmutableMap; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.util.expiring.Duration; -import fr.xephi.authme.util.message.I18NUtils; -import fr.xephi.authme.util.message.MiniMessageUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * Class for retrieving and sending translatable messages to players. - */ -public class Messages { - - // Custom Authme tag replaced to new line - private static final String NEWLINE_TAG = "%nl%"; - - // Global tag replacements - private static final String USERNAME_TAG = "%username%"; - private static final String DISPLAYNAME_TAG = "%displayname%"; - - /** Contains the keys of the singular messages for time units. */ - private static final Map TIME_UNIT_SINGULARS = ImmutableMap.builder() - .put(TimeUnit.SECONDS, MessageKey.SECOND) - .put(TimeUnit.MINUTES, MessageKey.MINUTE) - .put(TimeUnit.HOURS, MessageKey.HOUR) - .put(TimeUnit.DAYS, MessageKey.DAY).build(); - - /** Contains the keys of the plural messages for time units. */ - private static final Map TIME_UNIT_PLURALS = ImmutableMap.builder() - .put(TimeUnit.SECONDS, MessageKey.SECONDS) - .put(TimeUnit.MINUTES, MessageKey.MINUTES) - .put(TimeUnit.HOURS, MessageKey.HOURS) - .put(TimeUnit.DAYS, MessageKey.DAYS).build(); - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(EmailService.class); - - private MessagesFileHandler messagesFileHandler; - - /* - * Constructor. - */ - @Inject - Messages(MessagesFileHandler messagesFileHandler) { - this.messagesFileHandler = messagesFileHandler; - } - - /** - * Send the given message code to the player. - * - * @param sender The entity to send the message to - * @param key The key of the message to send - */ - public void send(CommandSender sender, MessageKey key) { - String[] lines = retrieve(key, sender); - for (String line : lines) { - sender.sendMessage(line); - } - } - - /** - * Send the given message code to the player with the given tag replacements. Note that this method - * logs an error if the number of supplied replacements doesn't correspond to the number of tags - * the message key contains. - * - * @param sender The entity to send the message to - * @param key The key of the message to send - * @param replacements The replacements to apply for the tags - */ - public void send(CommandSender sender, MessageKey key, String... replacements) { - String message = retrieveSingle(sender, key, replacements); - for (String line : message.split("\n")) { - sender.sendMessage(line); - } - } - - /** - * Retrieve the message from the text file and return it split by new line as an array. - * - * @param key The message key to retrieve - * @param sender The entity to send the message to - * @return The message split by new lines - */ - public String[] retrieve(MessageKey key, CommandSender sender) { - String message = retrieveMessage(key, sender); - if (message.isEmpty()) { - // Return empty array instead of array with 1 empty string as entry - return new String[0]; - } - return message.split("\n"); - } - - /** - * Returns the textual representation for the given duration. - * Note that this class only supports the time units days, hour, minutes and seconds. - * - * @param duration the duration to build a text of - * @return text of the duration - */ - public String formatDuration(Duration duration) { - long value = duration.getDuration(); - MessageKey timeUnitKey = value == 1 - ? TIME_UNIT_SINGULARS.get(duration.getTimeUnit()) - : TIME_UNIT_PLURALS.get(duration.getTimeUnit()); - - return value + " " + retrieveMessage(timeUnitKey, ""); - } - - /** - * Retrieve the message from the text file. - * - * @param key The message key to retrieve - * @param sender The entity to send the message to - * @return The message from the file - */ - private String retrieveMessage(MessageKey key, CommandSender sender) { - String locale = sender instanceof Player - ? I18NUtils.getLocale((Player) sender) - : null; - String message = messagesFileHandler.getMessageByLocale(key.getKey(), locale); - String displayName = sender.getName(); - if (sender instanceof Player) { - displayName = ((Player) sender).getDisplayName(); - } - - return ChatColor.translateAlternateColorCodes('&', MiniMessageUtils.parseMiniMessageToLegacy(message)) - .replace(NEWLINE_TAG, "\n") - .replace(USERNAME_TAG, sender.getName()) - .replace(DISPLAYNAME_TAG, displayName); - } - - /** - * Retrieve the message from the text file. - * - * @param key The message key to retrieve - * @param name The name of the entity to send the message to - * @return The message from the file - */ - private String retrieveMessage(MessageKey key, String name) { - String message = messagesFileHandler.getMessage(key.getKey()); - - return ChatColor.translateAlternateColorCodes('&', MiniMessageUtils.parseMiniMessageToLegacy(message)) - .replace(NEWLINE_TAG, "\n") - .replace(USERNAME_TAG, name) - .replace(DISPLAYNAME_TAG, name); - } - - /** - * Retrieve the given message code with the given tag replacements. Note that this method - * logs an error if the number of supplied replacements doesn't correspond to the number of tags - * the message key contains. - * - * @param sender The entity to send the message to - * @param key The key of the message to send - * @param replacements The replacements to apply for the tags - * @return The message from the file with replacements - */ - public String retrieveSingle(CommandSender sender, MessageKey key, String... replacements) { - String message = retrieveMessage(key, sender); - String[] tags = key.getTags(); - if (replacements.length == tags.length) { - for (int i = 0; i < tags.length; ++i) { - message = message.replace(tags[i], replacements[i]); - } - } else { - logger.warning("Invalid number of replacements for message key '" + key + "'"); - } - return message; - } - - /** - * Retrieve the given message code with the given tag replacements. Note that this method - * logs an error if the number of supplied replacements doesn't correspond to the number of tags - * the message key contains. - * - * @param name The name of the entity to send the message to - * @param key The key of the message to send - * @param replacements The replacements to apply for the tags - * @return The message from the file with replacements - */ - public String retrieveSingle(String name, MessageKey key, String... replacements) { - String message = retrieveMessage(key, name); - String[] tags = key.getTags(); - if (replacements.length == tags.length) { - for (int i = 0; i < tags.length; ++i) { - message = message.replace(tags[i], replacements[i]); - } - } else { - logger.warning("Invalid number of replacements for message key '" + key + "'"); - } - return message; - } -} diff --git a/src/main/java/fr/xephi/authme/message/MessagesFileHandler.java b/src/main/java/fr/xephi/authme/message/MessagesFileHandler.java deleted file mode 100644 index b62be93f..00000000 --- a/src/main/java/fr/xephi/authme/message/MessagesFileHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.message; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.message.updater.MessageUpdater; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -import javax.inject.Inject; - -import static fr.xephi.authme.message.MessagePathHelper.DEFAULT_LANGUAGE; - -/** - * File handler for the messages_xx.yml resource. - */ -public class MessagesFileHandler extends AbstractMessageFileHandler { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(MessagesFileHandler.class); - - @Inject - private MessageUpdater messageUpdater; - - MessagesFileHandler() { - } - - @Override - public void reload() { - reloadInternal(false); - } - - private void reloadInternal(boolean isFromReload) { - super.reload(); - - String language = getLanguage(); - boolean hasChange = messageUpdater.migrateAndSave( - getUserLanguageFile(), createFilePath(language), createFilePath(DEFAULT_LANGUAGE)); - if (hasChange) { - if (isFromReload) { - logger.warning("Migration after reload attempt"); - } else { - reloadInternal(true); - } - } - } - - @Override - protected String createFilePath(String language) { - return MessagePathHelper.createMessageFilePath(language); - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java b/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java deleted file mode 100644 index 73075f4e..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java +++ /dev/null @@ -1,59 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.properties.Property; -import ch.jalu.configme.resource.PropertyReader; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.util.FileUtils; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Returns messages from the JAR's message files. Favors a local JAR (e.g. messages_nl.yml) - * before falling back to the default language (messages_en.yml). - */ -public class JarMessageSource { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(JarMessageSource.class); - private final PropertyReader localJarMessages; - private final PropertyReader defaultJarMessages; - - /** - * Constructor. - * - * @param localJarPath path to the messages file of the language the plugin is configured to use (may not exist) - * @param defaultJarPath path to the default messages file in the JAR (must exist) - */ - public JarMessageSource(String localJarPath, String defaultJarPath) { - localJarMessages = localJarPath.equals(defaultJarPath) ? null : loadJarFile(localJarPath); - defaultJarMessages = loadJarFile(defaultJarPath); - - if (defaultJarMessages == null) { - throw new IllegalStateException("Default JAR file '" + defaultJarPath + "' could not be loaded"); - } - } - - public String getMessageFromJar(Property property) { - String key = property.getPath(); - String message = getString(key, localJarMessages); - return message == null ? getString(key, defaultJarMessages) : message; - } - - private static String getString(String path, PropertyReader reader) { - return reader == null ? null : reader.getString(path); - } - - private MessageMigraterPropertyReader loadJarFile(String jarPath) { - try (InputStream stream = FileUtils.getResourceFromJar(jarPath)) { - if (stream == null) { - logger.debug("Could not load '" + jarPath + "' from JAR"); - return null; - } - return MessageMigraterPropertyReader.loadFromStream(stream); - } catch (IOException e) { - logger.logException("Exception while handling JAR path '" + jarPath + "'", e); - } - return null; - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/MessageKeyConfigurationData.java b/src/main/java/fr/xephi/authme/message/updater/MessageKeyConfigurationData.java deleted file mode 100644 index cf3c1c78..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/MessageKeyConfigurationData.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.configurationdata.ConfigurationDataImpl; -import ch.jalu.configme.properties.Property; -import ch.jalu.configme.properties.convertresult.PropertyValue; -import ch.jalu.configme.resource.PropertyReader; -import fr.xephi.authme.message.MessageKey; - -import java.util.List; -import java.util.Map; - -public class MessageKeyConfigurationData extends ConfigurationDataImpl { - - /** - * Constructor. - * - * @param propertyListBuilder property list builder for message key properties - * @param allComments registered comments - */ - public MessageKeyConfigurationData(MessageUpdater.MessageKeyPropertyListBuilder propertyListBuilder, - Map> allComments) { - super(propertyListBuilder.getAllProperties(), allComments); - } - - @Override - public void initializeValues(PropertyReader reader) { - for (Property property : getAllMessageProperties()) { - PropertyValue value = property.determineValue(reader); - if (value.isValidInResource()) { - setValue(property, value.getValue()); - } - } - } - - @Override - public T getValue(Property property) { - // Override to silently return null if property is unknown - return (T) getValues().get(property.getPath()); - } - - @SuppressWarnings("unchecked") - public List> getAllMessageProperties() { - return (List) getProperties(); - } - - public String getMessage(MessageKey messageKey) { - return getValue(new MessageUpdater.MessageKeyProperty(messageKey)); - } - - public void setMessage(MessageKey messageKey, String message) { - setValue(new MessageUpdater.MessageKeyProperty(messageKey), message); - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/MessageMigraterPropertyReader.java b/src/main/java/fr/xephi/authme/message/updater/MessageMigraterPropertyReader.java deleted file mode 100644 index a994df89..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/MessageMigraterPropertyReader.java +++ /dev/null @@ -1,126 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.exception.ConfigMeException; -import ch.jalu.configme.resource.PropertyReader; -import org.yaml.snakeyaml.Yaml; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Implementation of {@link PropertyReader} which can read a file or a stream with - * a specified charset. - */ -final class MessageMigraterPropertyReader implements PropertyReader { - - private static final Charset CHARSET = StandardCharsets.UTF_8; - - private Map root; - - private MessageMigraterPropertyReader(Map valuesMap) { - root = valuesMap; - } - - /** - * Creates a new property reader for the given file. - * - * @param file the file to load - * @return the created property reader - */ - public static MessageMigraterPropertyReader loadFromFile(File file) { - try (InputStream is = new FileInputStream(file)) { - return loadFromStream(is); - } catch (IOException e) { - throw new IllegalStateException("Error while reading file '" + file + "'", e); - } - } - - public static MessageMigraterPropertyReader loadFromStream(InputStream inputStream) { - Map valuesMap = readStreamToMap(inputStream); - return new MessageMigraterPropertyReader(valuesMap); - } - - @Override - public boolean contains(String path) { - return getObject(path) != null; - } - - @Override - public Set getKeys(boolean b) { - throw new UnsupportedOperationException(); - } - - @Override - public Set getChildKeys(String s) { - throw new UnsupportedOperationException(); - } - - @Override - public Object getObject(String path) { - if (path.isEmpty()) { - return root.get(""); - } - Object node = root; - String[] keys = path.split("\\."); - for (String key : keys) { - node = getIfIsMap(key, node); - if (node == null) { - return null; - } - } - return node; - } - - @Override - public String getString(String path) { - Object o = getObject(path); - return o instanceof String ? (String) o : null; - } - - @Override - public Integer getInt(String path) { - throw new UnsupportedOperationException(); - } - - @Override - public Double getDouble(String path) { - throw new UnsupportedOperationException(); - } - - @Override - public Boolean getBoolean(String path) { - throw new UnsupportedOperationException(); - } - - @Override - public List getList(String path) { - throw new UnsupportedOperationException(); - } - - private static Map readStreamToMap(InputStream inputStream) { - try (InputStreamReader isr = new InputStreamReader(inputStream, CHARSET)) { - Object obj = new Yaml().load(isr); - return obj == null ? new HashMap<>() : (Map) obj; - } catch (IOException e) { - throw new ConfigMeException("Could not read stream", e); - } catch (ClassCastException e) { - throw new ConfigMeException("Top-level is not a map", e); - } - } - - private static Object getIfIsMap(String key, Object value) { - if (value instanceof Map) { - return ((Map) value).get(key); - } - return null; - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java b/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java deleted file mode 100644 index f3f718c8..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java +++ /dev/null @@ -1,202 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.configurationdata.PropertyListBuilder; -import ch.jalu.configme.properties.Property; -import ch.jalu.configme.properties.StringProperty; -import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; -import ch.jalu.configme.resource.PropertyReader; -import ch.jalu.configme.resource.PropertyResource; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.Files; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.util.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.util.Collections.singletonList; - -/** - * Migrates the used messages file to a complete, up-to-date version when necessary. - */ -public class MessageUpdater { - - private ConsoleLogger logger = ConsoleLoggerFactory.get(MessageUpdater.class); - - /** - * Applies any necessary migrations to the user's messages file and saves it if it has been modified. - * - * @param userFile the user's messages file (yml file in the plugin's folder) - * @param localJarPath path to the messages file in the JAR for the same language (may not exist) - * @param defaultJarPath path to the messages file in the JAR for the default language - * @return true if the file has been migrated and saved, false if it is up-to-date - */ - public boolean migrateAndSave(File userFile, String localJarPath, String defaultJarPath) { - JarMessageSource jarMessageSource = new JarMessageSource(localJarPath, defaultJarPath); - return migrateAndSave(userFile, jarMessageSource); - } - - /** - * Performs the migration. - * - * @param userFile the file to verify and migrate - * @param jarMessageSource jar message source to get texts from if missing - * @return true if the file has been migrated and saved, false if it is up-to-date - */ - private boolean migrateAndSave(File userFile, JarMessageSource jarMessageSource) { - // YamlConfiguration escapes all special characters when saving, making the file hard to use, so use ConfigMe - MessageKeyConfigurationData configurationData = createConfigurationData(); - PropertyResource userResource = new MigraterYamlFileResource(userFile); - - PropertyReader reader = userResource.createReader(); - configurationData.initializeValues(reader); - - // Step 1: Migrate any old keys in the file to the new paths - boolean movedOldKeys = migrateOldKeys(reader, configurationData); - // Step 2: Perform newer migrations - boolean movedNewerKeys = migrateKeys(reader, configurationData); - // Step 3: Take any missing messages from the message files shipped in the AuthMe JAR - boolean addedMissingKeys = addMissingKeys(jarMessageSource, configurationData); - - if (movedOldKeys || movedNewerKeys || addedMissingKeys) { - backupMessagesFile(userFile); - - userResource.exportProperties(configurationData); - logger.debug("Successfully saved {0}", userFile); - return true; - } - return false; - } - - private boolean migrateKeys(PropertyReader propertyReader, MessageKeyConfigurationData configurationData) { - return moveIfApplicable(propertyReader, configurationData, - "misc.two_factor_create", MessageKey.TWO_FACTOR_CREATE); - } - - private static boolean moveIfApplicable(PropertyReader reader, MessageKeyConfigurationData configurationData, - String oldPath, MessageKey messageKey) { - if (configurationData.getMessage(messageKey) == null && reader.getString(oldPath) != null) { - configurationData.setMessage(messageKey, reader.getString(oldPath)); - return true; - } - return false; - } - - private boolean migrateOldKeys(PropertyReader propertyReader, MessageKeyConfigurationData configurationData) { - boolean hasChange = OldMessageKeysMigrater.migrateOldPaths(propertyReader, configurationData); - if (hasChange) { - logger.info("Old keys have been moved to the new ones in your messages_xx.yml file"); - } - return hasChange; - } - - private boolean addMissingKeys(JarMessageSource jarMessageSource, MessageKeyConfigurationData configurationData) { - List addedKeys = new ArrayList<>(); - for (Property property : configurationData.getAllMessageProperties()) { - final String key = property.getPath(); - if (configurationData.getValue(property) == null) { - configurationData.setValue(property, jarMessageSource.getMessageFromJar(property)); - addedKeys.add(key); - } - } - if (!addedKeys.isEmpty()) { - logger.info( - "Added " + addedKeys.size() + " missing keys to your messages_xx.yml file: " + addedKeys); - return true; - } - return false; - } - - private static void backupMessagesFile(File messagesFile) { - String backupName = FileUtils.createBackupFilePath(messagesFile); - File backupFile = new File(backupName); - try { - Files.copy(messagesFile, backupFile); - } catch (IOException e) { - throw new IllegalStateException("Could not back up '" + messagesFile + "' to '" + backupFile + "'", e); - } - } - - /** - * Constructs the {@link ConfigurationData} for exporting a messages file in its entirety. - * - * @return the configuration data to export with - */ - public static MessageKeyConfigurationData createConfigurationData() { - Map comments = ImmutableMap.builder() - .put("registration", "Registration") - .put("password", "Password errors on registration") - .put("login", "Login") - .put("error", "Errors") - .put("antibot", "AntiBot") - .put("unregister", "Unregister") - .put("misc", "Other messages") - .put("session", "Session messages") - .put("on_join_validation", "Error messages when joining") - .put("email", "Email") - .put("recovery", "Password recovery by email") - .put("captcha", "Captcha") - .put("verification", "Verification code") - .put("time", "Time units") - .put("two_factor", "Two-factor authentication") - .put("bedrock_auto_login", "3rd party features: Bedrock Auto Login") - .put("login_location_fix", "3rd party features: Login Location Fix") - .put("double_login_fix", "3rd party features: Double Login Fix") - .build(); - - Set addedKeys = new HashSet<>(); - MessageKeyPropertyListBuilder builder = new MessageKeyPropertyListBuilder(); - // Add one key per section based on the comments map above so that the order is clear - for (String path : comments.keySet()) { - MessageKey key = Arrays.stream(MessageKey.values()).filter(p -> p.getKey().startsWith(path + ".")) - .findFirst().orElseThrow(() -> new IllegalStateException(path)); - builder.addMessageKey(key); - addedKeys.add(key.getKey()); - } - // Add all remaining keys to the property list builder - Arrays.stream(MessageKey.values()) - .filter(key -> !addedKeys.contains(key.getKey())) - .forEach(builder::addMessageKey); - - // Create ConfigurationData instance - Map> commentsMap = comments.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> singletonList(e.getValue()))); - return new MessageKeyConfigurationData(builder, commentsMap); - } - - static final class MessageKeyProperty extends StringProperty { - - MessageKeyProperty(MessageKey messageKey) { - super(messageKey.getKey(), ""); - } - - @Override - protected String getFromReader(PropertyReader reader, ConvertErrorRecorder errorRecorder) { - return reader.getString(getPath()); - } - } - - static final class MessageKeyPropertyListBuilder { - - private PropertyListBuilder propertyListBuilder = new PropertyListBuilder(); - - void addMessageKey(MessageKey key) { - propertyListBuilder.add(new MessageKeyProperty(key)); - } - - @SuppressWarnings("unchecked") - List getAllProperties() { - return (List) propertyListBuilder.create(); - } - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/MigraterYamlFileResource.java b/src/main/java/fr/xephi/authme/message/updater/MigraterYamlFileResource.java deleted file mode 100644 index b0122215..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/MigraterYamlFileResource.java +++ /dev/null @@ -1,47 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.resource.PropertyReader; -import ch.jalu.configme.resource.YamlFileResource; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; - -import java.io.File; - -/** - * Extension of {@link YamlFileResource} to fine-tune the export style. - */ -public class MigraterYamlFileResource extends YamlFileResource { - - private Yaml singleQuoteYaml; - - public MigraterYamlFileResource(File file) { - super(file); - } - - @Override - public PropertyReader createReader() { - return MessageMigraterPropertyReader.loadFromFile(getFile()); - } - - @Override - protected Yaml createNewYaml() { - if (singleQuoteYaml == null) { - DumperOptions options = new DumperOptions(); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - options.setAllowUnicode(true); - options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); - // Overridden setting: don't split lines - options.setSplitLines(false); - singleQuoteYaml = new Yaml(options); - } - return singleQuoteYaml; - } - - // Because we set the YAML object to put strings in single quotes, this method by default uses that YAML object - // and also puts all paths as single quotes. Override to just always return the same string since we know those - // are only message names (so never any conflicting strings like "true" or "0"). - @Override - protected String escapePathElementIfNeeded(String path) { - return path; - } -} diff --git a/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java b/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java deleted file mode 100644 index 739a449d..00000000 --- a/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java +++ /dev/null @@ -1,170 +0,0 @@ -package fr.xephi.authme.message.updater; - -import ch.jalu.configme.resource.PropertyReader; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; -import fr.xephi.authme.message.MessageKey; - -import java.util.Map; - -import static com.google.common.collect.ImmutableMap.of; - -/** - * Migrates message files from the old keys (before 5.5) to the new ones. - * - * @see Issue #1467 - */ -final class OldMessageKeysMigrater { - - @VisibleForTesting - static final Map KEYS_TO_OLD_PATH = ImmutableMap.builder() - .put(MessageKey.LOGIN_SUCCESS, "login") - .put(MessageKey.ERROR, "error") - .put(MessageKey.DENIED_COMMAND, "denied_command") - .put(MessageKey.SAME_IP_ONLINE, "same_ip_online") - .put(MessageKey.DENIED_CHAT, "denied_chat") - .put(MessageKey.KICK_ANTIBOT, "kick_antibot") - .put(MessageKey.UNKNOWN_USER, "unknown_user") - .put(MessageKey.NOT_LOGGED_IN, "not_logged_in") - .put(MessageKey.USAGE_LOGIN, "usage_log") - .put(MessageKey.WRONG_PASSWORD, "wrong_pwd") - .put(MessageKey.UNREGISTERED_SUCCESS, "unregistered") - .put(MessageKey.REGISTRATION_DISABLED, "reg_disabled") - .put(MessageKey.SESSION_RECONNECTION, "valid_session") - .put(MessageKey.ACCOUNT_NOT_ACTIVATED, "vb_nonActiv") - .put(MessageKey.NAME_ALREADY_REGISTERED, "user_regged") - .put(MessageKey.NO_PERMISSION, "no_perm") - .put(MessageKey.LOGIN_MESSAGE, "login_msg") - .put(MessageKey.REGISTER_MESSAGE, "reg_msg") - .put(MessageKey.MAX_REGISTER_EXCEEDED, "max_reg") - .put(MessageKey.USAGE_REGISTER, "usage_reg") - .put(MessageKey.USAGE_UNREGISTER, "usage_unreg") - .put(MessageKey.PASSWORD_CHANGED_SUCCESS, "pwd_changed") - .put(MessageKey.PASSWORD_MATCH_ERROR, "password_error") - .put(MessageKey.PASSWORD_IS_USERNAME_ERROR, "password_error_nick") - .put(MessageKey.PASSWORD_UNSAFE_ERROR, "password_error_unsafe") - .put(MessageKey.PASSWORD_CHARACTERS_ERROR, "password_error_chars") - .put(MessageKey.SESSION_EXPIRED, "invalid_session") - .put(MessageKey.MUST_REGISTER_MESSAGE, "reg_only") - .put(MessageKey.ALREADY_LOGGED_IN_ERROR, "logged_in") - .put(MessageKey.LOGOUT_SUCCESS, "logout") - .put(MessageKey.USERNAME_ALREADY_ONLINE_ERROR, "same_nick") - .put(MessageKey.REGISTER_SUCCESS, "registered") - .put(MessageKey.INVALID_PASSWORD_LENGTH, "pass_len") - .put(MessageKey.CONFIG_RELOAD_SUCCESS, "reload") - .put(MessageKey.LOGIN_TIMEOUT_ERROR, "timeout") - .put(MessageKey.USAGE_CHANGE_PASSWORD, "usage_changepassword") - .put(MessageKey.INVALID_NAME_LENGTH, "name_len") - .put(MessageKey.INVALID_NAME_CHARACTERS, "regex") - .put(MessageKey.ADD_EMAIL_MESSAGE, "add_email") - .put(MessageKey.FORGOT_PASSWORD_MESSAGE, "recovery_email") - .put(MessageKey.USAGE_CAPTCHA, "usage_captcha") - .put(MessageKey.CAPTCHA_WRONG_ERROR, "wrong_captcha") - .put(MessageKey.CAPTCHA_SUCCESS, "valid_captcha") - .put(MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED, "captcha_for_registration") - .put(MessageKey.REGISTER_CAPTCHA_SUCCESS, "register_captcha_valid") - .put(MessageKey.KICK_FOR_VIP, "kick_forvip") - .put(MessageKey.KICK_FULL_SERVER, "kick_fullserver") - .put(MessageKey.USAGE_ADD_EMAIL, "usage_email_add") - .put(MessageKey.USAGE_CHANGE_EMAIL, "usage_email_change") - .put(MessageKey.USAGE_RECOVER_EMAIL, "usage_email_recovery") - .put(MessageKey.INVALID_NEW_EMAIL, "new_email_invalid") - .put(MessageKey.INVALID_OLD_EMAIL, "old_email_invalid") - .put(MessageKey.INVALID_EMAIL, "email_invalid") - .put(MessageKey.EMAIL_ADDED_SUCCESS, "email_added") - .put(MessageKey.CONFIRM_EMAIL_MESSAGE, "email_confirm") - .put(MessageKey.EMAIL_CHANGED_SUCCESS, "email_changed") - .put(MessageKey.EMAIL_SHOW, "email_show") - .put(MessageKey.SHOW_NO_EMAIL, "show_no_email") - .put(MessageKey.RECOVERY_EMAIL_SENT_MESSAGE, "email_send") - .put(MessageKey.COUNTRY_BANNED_ERROR, "country_banned") - .put(MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE, "antibot_auto_enabled") - .put(MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE, "antibot_auto_disabled") - .put(MessageKey.EMAIL_ALREADY_USED_ERROR, "email_already_used") - .put(MessageKey.TWO_FACTOR_CREATE, "two_factor_create") - .put(MessageKey.NOT_OWNER_ERROR, "not_owner_error") - .put(MessageKey.INVALID_NAME_CASE, "invalid_name_case") - .put(MessageKey.TEMPBAN_MAX_LOGINS, "tempban_max_logins") - .put(MessageKey.ACCOUNTS_OWNED_SELF, "accounts_owned_self") - .put(MessageKey.ACCOUNTS_OWNED_OTHER, "accounts_owned_other") - .put(MessageKey.KICK_FOR_ADMIN_REGISTER, "kicked_admin_registered") - .put(MessageKey.INCOMPLETE_EMAIL_SETTINGS, "incomplete_email_settings") - .put(MessageKey.EMAIL_SEND_FAILURE, "email_send_failure") - .put(MessageKey.RECOVERY_CODE_SENT, "recovery_code_sent") - .put(MessageKey.INCORRECT_RECOVERY_CODE, "recovery_code_incorrect") - .put(MessageKey.RECOVERY_TRIES_EXCEEDED, "recovery_tries_exceeded") - .put(MessageKey.RECOVERY_CODE_CORRECT, "recovery_code_correct") - .put(MessageKey.RECOVERY_CHANGE_PASSWORD, "recovery_change_password") - .put(MessageKey.CHANGE_PASSWORD_EXPIRED, "change_password_expired") - .put(MessageKey.EMAIL_COOLDOWN_ERROR, "email_cooldown_error") - .put(MessageKey.VERIFICATION_CODE_REQUIRED, "verification_code_required") - .put(MessageKey.USAGE_VERIFICATION_CODE, "usage_verification_code") - .put(MessageKey.INCORRECT_VERIFICATION_CODE, "incorrect_verification_code") - .put(MessageKey.VERIFICATION_CODE_VERIFIED, "verification_code_verified") - .put(MessageKey.VERIFICATION_CODE_ALREADY_VERIFIED, "verification_code_already_verified") - .put(MessageKey.VERIFICATION_CODE_EXPIRED, "verification_code_expired") - .put(MessageKey.VERIFICATION_CODE_EMAIL_NEEDED, "verification_code_email_needed") - .put(MessageKey.SECOND, "second") - .put(MessageKey.SECONDS, "seconds") - .put(MessageKey.MINUTE, "minute") - .put(MessageKey.MINUTES, "minutes") - .put(MessageKey.HOUR, "hour") - .put(MessageKey.HOURS, "hours") - .put(MessageKey.DAY, "day") - .put(MessageKey.DAYS, "days") - .build(); - - private static final Map> PLACEHOLDER_REPLACEMENTS = - ImmutableMap.>builder() - .put(MessageKey.PASSWORD_CHARACTERS_ERROR, of("REG_EX", "%valid_chars")) - .put(MessageKey.INVALID_NAME_CHARACTERS, of("REG_EX", "%valid_chars")) - .put(MessageKey.USAGE_CAPTCHA, of("", "%captcha_code")) - .put(MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED, of("", "%captcha_code")) - .put(MessageKey.CAPTCHA_WRONG_ERROR, of("THE_CAPTCHA", "%captcha_code")) - .build(); - - private OldMessageKeysMigrater() { - } - - /** - * Migrates any existing old key paths to their new paths if no text has been defined for the new key. - * - * @param reader the property reader to get values from - * @param configurationData the configuration data to write to - * @return true if at least one message could be migrated, false otherwise - */ - static boolean migrateOldPaths(PropertyReader reader, MessageKeyConfigurationData configurationData) { - boolean wasPropertyMoved = false; - for (Map.Entry migrationEntry : KEYS_TO_OLD_PATH.entrySet()) { - wasPropertyMoved |= moveIfApplicable(reader, configurationData, - migrationEntry.getKey(), migrationEntry.getValue()); - } - return wasPropertyMoved; - } - - private static boolean moveIfApplicable(PropertyReader reader, MessageKeyConfigurationData configurationData, - MessageKey messageKey, String oldPath) { - if (configurationData.getMessage(messageKey) == null) { - String textAtOldPath = reader.getString(oldPath); - if (textAtOldPath != null) { - textAtOldPath = replaceOldPlaceholders(messageKey, textAtOldPath); - configurationData.setMessage(messageKey, textAtOldPath); - return true; - } - } - return false; - } - - private static String replaceOldPlaceholders(MessageKey key, String text) { - Map replacements = PLACEHOLDER_REPLACEMENTS.get(key); - if (replacements == null) { - return text; - } - - String newText = text; - for (Map.Entry replacement : replacements.entrySet()) { - newText = newText.replace(replacement.getKey(), replacement.getValue()); - } - return newText; - } -} diff --git a/src/main/java/fr/xephi/authme/output/ConsoleFilter.java b/src/main/java/fr/xephi/authme/output/ConsoleFilter.java deleted file mode 100644 index 975cc4cc..00000000 --- a/src/main/java/fr/xephi/authme/output/ConsoleFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.xephi.authme.output; - -import java.util.logging.Filter; -import java.util.logging.LogRecord; - -/** - * Console filter to replace sensitive AuthMe commands with a generic message. - * - * @author Xephi59 - */ -public class ConsoleFilter implements Filter { - - @Override - public boolean isLoggable(LogRecord record) { - if (record == null || record.getMessage() == null) { - return true; - } - - if (LogFilterHelper.isSensitiveAuthMeCommand(record.getMessage())) { - String playerName = record.getMessage().split(" ")[0]; - record.setMessage(playerName + " issued an AuthMe command"); - } - return true; - } - -} diff --git a/src/main/java/fr/xephi/authme/output/ConsoleLoggerFactory.java b/src/main/java/fr/xephi/authme/output/ConsoleLoggerFactory.java deleted file mode 100644 index fb51043d..00000000 --- a/src/main/java/fr/xephi/authme/output/ConsoleLoggerFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -package fr.xephi.authme.output; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.Settings; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Creates and keeps track of {@link ConsoleLogger} instances. - */ -public final class ConsoleLoggerFactory { - - private static final Map consoleLoggers = new ConcurrentHashMap<>(); - private static Settings settings; - - private ConsoleLoggerFactory() { - } - - /** - * Creates or returns the already existing logger associated with the given class. - * - * @param owningClass the class whose logger should be retrieved - * @return logger for the given class - */ - public static ConsoleLogger get(Class owningClass) { - String name = owningClass.getCanonicalName(); - return consoleLoggers.computeIfAbsent(name, ConsoleLoggerFactory::createLogger); - } - - /** - * Sets up all loggers according to the properties returned by the settings instance. - * - * @param settings the settings instance - */ - public static void reloadSettings(Settings settings) { - ConsoleLoggerFactory.settings = settings; - ConsoleLogger.initializeSharedSettings(settings); - - consoleLoggers.values() - .forEach(logger -> logger.initializeSettings(settings)); - } - - public static int getTotalLoggers() { - return consoleLoggers.size(); - } - - private static ConsoleLogger createLogger(String name) { - ConsoleLogger logger = new ConsoleLogger(name); - if (settings != null) { - logger.initializeSettings(settings); - } - return logger; - } -} diff --git a/src/main/java/fr/xephi/authme/output/Log4JFilter.java b/src/main/java/fr/xephi/authme/output/Log4JFilter.java deleted file mode 100644 index 1ebf5141..00000000 --- a/src/main/java/fr/xephi/authme/output/Log4JFilter.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.output; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.filter.AbstractFilter; -import org.apache.logging.log4j.message.Message; - -/** - * Implements a filter for Log4j to skip sensitive AuthMe commands. - * - * @author Xephi59 - */ -public class Log4JFilter extends AbstractFilter { - - private static final long serialVersionUID = -5594073755007974254L; - - /** - * Validates a Message instance and returns the {@link Result} value - * depending on whether the message contains sensitive AuthMe data. - * - * @param message The Message object to verify - * - * @return The Result value - */ - private static Result validateMessage(Message message) { - if (message == null) { - return Result.NEUTRAL; - } - return validateMessage(message.getFormattedMessage()); - } - - /** - * Validates a message and returns the {@link Result} value depending - * on whether the message contains sensitive AuthMe data. - * - * @param message The message to verify - * - * @return The Result value - */ - private static Result validateMessage(String message) { - return LogFilterHelper.isSensitiveAuthMeCommand(message) - ? Result.DENY - : Result.NEUTRAL; - } - - @Override - public Result filter(LogEvent event) { - Message candidate = null; - if (event != null) { - candidate = event.getMessage(); - } - return validateMessage(candidate); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { - return validateMessage(msg); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) { - return validateMessage(msg); - } - - @Override - public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { - String candidate = null; - if (msg != null) { - candidate = msg.toString(); - } - return validateMessage(candidate); - } -} diff --git a/src/main/java/fr/xephi/authme/output/LogFilterHelper.java b/src/main/java/fr/xephi/authme/output/LogFilterHelper.java deleted file mode 100644 index 6058584a..00000000 --- a/src/main/java/fr/xephi/authme/output/LogFilterHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.output; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.util.StringUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -/** - * Service class for the log filters. - */ -final class LogFilterHelper { - - @VisibleForTesting - static final List COMMANDS_TO_SKIP = withAndWithoutAuthMePrefix( - "/login ", "/l ", "/log ", "/register ", "/reg ", "/unregister ", "/unreg ", - "/changepassword ", "/cp ", "/changepass ", "/authme register ", "/authme reg ", "/authme r ", - "/authme changepassword ", "/authme password ", "/authme changepass ", "/authme cp ", "/email setpassword "); - - private static final String ISSUED_COMMAND_TEXT = "issued server command:"; - - private LogFilterHelper() { - // Util class - } - - /** - * Validate a message and return whether the message contains a sensitive AuthMe command. - * - * @param message The message to verify - * - * @return True if it is a sensitive AuthMe command, false otherwise - */ - static boolean isSensitiveAuthMeCommand(String message) { - if (message == null) { - return false; - } - String lowerMessage = message.toLowerCase(Locale.ROOT); - return lowerMessage.contains(ISSUED_COMMAND_TEXT) && StringUtils.containsAny(lowerMessage, COMMANDS_TO_SKIP); - } - - private static List withAndWithoutAuthMePrefix(String... commands) { - List commandList = new ArrayList<>(commands.length * 2); - for (String command : commands) { - commandList.add(command); - commandList.add(command.substring(0, 1) + "authme:" + command.substring(1)); - } - return Collections.unmodifiableList(commandList); - } -} diff --git a/src/main/java/fr/xephi/authme/output/LogLevel.java b/src/main/java/fr/xephi/authme/output/LogLevel.java deleted file mode 100644 index f958e6d4..00000000 --- a/src/main/java/fr/xephi/authme/output/LogLevel.java +++ /dev/null @@ -1,38 +0,0 @@ -package fr.xephi.authme.output; - -/** - * Log level. - */ -public enum LogLevel { - - /** Info: general messages. */ - INFO(3), - - /** Fine: more detailed messages that may still be interesting to plugin users. */ - FINE(2), - - /** Debug: very detailed messages for debugging. */ - DEBUG(1); - - private int value; - - /** - * Constructor. - * - * @param value the log level; the higher the number the more "important" the level. - * A log level enables its number and all above. - */ - LogLevel(int value) { - this.value = value; - } - - /** - * Return whether the current log level includes the given log level. - * - * @param level the level to process - * @return true if the level is enabled, false otherwise - */ - public boolean includes(LogLevel level) { - return value <= level.value; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/AdminPermission.java b/src/main/java/fr/xephi/authme/permission/AdminPermission.java deleted file mode 100644 index 20e27f2f..00000000 --- a/src/main/java/fr/xephi/authme/permission/AdminPermission.java +++ /dev/null @@ -1,166 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * AuthMe admin command permissions. - */ -public enum AdminPermission implements PermissionNode { - - /** - * Administrator command to register a new user. - */ - REGISTER("authme.admin.register"), - - /** - * Administrator command to unregister an existing user. - */ - UNREGISTER("authme.admin.unregister"), - - /** - * Administrator command to force-login an existing user. - */ - FORCE_LOGIN("authme.admin.forcelogin"), - - /** - * Administrator command to change the password of a user. - */ - CHANGE_PASSWORD("authme.admin.changepassword"), - - /** - * Administrator command to see the last login date and time of a user. - */ - LAST_LOGIN("authme.admin.lastlogin"), - - /** - * Administrator command to see all accounts associated with a user. - */ - ACCOUNTS("authme.admin.accounts"), - - /** - * Administrator command to get the email address of a user, if set. - */ - GET_EMAIL("authme.admin.getemail"), - - /** - * Administrator command to set or change the email address of a user. - */ - CHANGE_EMAIL("authme.admin.changemail"), - - /** - * Administrator command to see whether a player has enabled two-factor authentication. - */ - VIEW_TOTP_STATUS("authme.admin.totpviewstatus"), - - /** - * Administrator command to disable the two-factor auth of a user. - */ - DISABLE_TOTP("authme.admin.totpdisable"), - - /** - * Administrator command to get the last known IP of a user. - */ - GET_IP("authme.admin.getip"), - - /** - * Administrator command to see the last recently logged in players. - */ - SEE_RECENT_PLAYERS("authme.admin.seerecent"), - - /** - * Administrator command to teleport to the AuthMe spawn. - */ - SPAWN("authme.admin.spawn"), - - /** - * Administrator command to set the AuthMe spawn. - */ - SET_SPAWN("authme.admin.setspawn"), - - /** - * Administrator command to teleport to the first AuthMe spawn. - */ - FIRST_SPAWN("authme.admin.firstspawn"), - - /** - * Administrator command to set the first AuthMe spawn. - */ - SET_FIRST_SPAWN("authme.admin.setfirstspawn"), - - /** - * Administrator command to purge old user data. - */ - PURGE("authme.admin.purge"), - - /** - * Administrator command to purge the last position of a user. - */ - PURGE_LAST_POSITION("authme.admin.purgelastpos"), - - /** - * Administrator command to purge all data associated with banned players. - */ - PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers"), - - /** - * Administrator command to purge a given player. - */ - PURGE_PLAYER("authme.admin.purgeplayer"), - - /** - * Administrator command to toggle the AntiBot protection status. - */ - SWITCH_ANTIBOT("authme.admin.switchantibot"), - - /** - * Administrator command to convert old or other data to AuthMe data. - */ - CONVERTER("authme.admin.converter"), - - /** - * Administrator command to reload the plugin configuration. - */ - RELOAD("authme.admin.reload"), - - /** - * Permission to see Antibot messages. - */ - ANTIBOT_MESSAGES("authme.admin.antibotmessages"), - - /** - * Permission to use the update messages command. - */ - UPDATE_MESSAGES("authme.admin.updatemessages"), - - /** - * Permission to see the other accounts of the players that log in. - */ - SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts"), - - /** - * Allows to use the backup command. - */ - BACKUP("authme.admin.backup"); - - /** - * The permission node. - */ - private String node; - - /** - * Constructor. - * - * @param node Permission node. - */ - AdminPermission(String node) { - this.node = node; - } - - @Override - public String getNode() { - return node; - } - - @Override - public DefaultPermission getDefaultPermission() { - return DefaultPermission.OP_ONLY; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/DebugSectionPermissions.java b/src/main/java/fr/xephi/authme/permission/DebugSectionPermissions.java deleted file mode 100644 index 6461c29a..00000000 --- a/src/main/java/fr/xephi/authme/permission/DebugSectionPermissions.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * Permissions for the debug sections (/authme debug). - */ -public enum DebugSectionPermissions implements PermissionNode { - - /** General permission to use the /authme debug command. */ - DEBUG_COMMAND("authme.debug.command"), - - /** Permission to use the country lookup section. */ - COUNTRY_LOOKUP("authme.debug.country"), - - /** Permission to use the stats section. */ - DATA_STATISTICS("authme.debug.stats"), - - /** Permission to use the permission checker. */ - HAS_PERMISSION_CHECK("authme.debug.perm"), - - /** Permission to use sample validation. */ - INPUT_VALIDATOR("authme.debug.valid"), - - /** Permission to use the limbo data viewer. */ - LIMBO_PLAYER_VIEWER("authme.debug.limbo"), - - /** Permission to view permission groups. */ - PERM_GROUPS("authme.debug.group"), - - /** Permission to view data from the database. */ - PLAYER_AUTH_VIEWER("authme.debug.db"), - - /** Permission to change nullable status of MySQL columns. */ - MYSQL_DEFAULT_CHANGER("authme.debug.mysqldef"), - - /** Permission to view spawn information. */ - SPAWN_LOCATION("authme.debug.spawn"), - - /** Permission to use the test email sender. */ - TEST_EMAIL("authme.debug.mail"); - - private final String node; - - /** - * Constructor. - * - * @param node the permission node - */ - DebugSectionPermissions(String node) { - this.node = node; - } - - @Override - public String getNode() { - return node; - } - - @Override - public DefaultPermission getDefaultPermission() { - return DefaultPermission.OP_ONLY; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java deleted file mode 100644 index 1d0e0f3e..00000000 --- a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java +++ /dev/null @@ -1,42 +0,0 @@ -package fr.xephi.authme.permission; - -import org.bukkit.permissions.ServerOperator; - -/** - * The default permission to fall back to if there is no support for permission nodes. - */ -public enum DefaultPermission { - - /** No one has permission. */ - NOT_ALLOWED { - @Override - public boolean evaluate(ServerOperator sender) { - return false; - } - }, - - /** Only players with OP status have permission. */ - OP_ONLY { - @Override - public boolean evaluate(ServerOperator sender) { - return sender != null && sender.isOp(); - } - }, - - /** Everyone is granted permission. */ - ALLOWED { - @Override - public boolean evaluate(ServerOperator sender) { - return true; - } - }; - - /** - * Evaluates whether permission is granted to the sender or not. - * - * @param sender the sender to process - * @return true if the sender has permission, false otherwise - */ - public abstract boolean evaluate(ServerOperator sender); - -} diff --git a/src/main/java/fr/xephi/authme/permission/PermissionNode.java b/src/main/java/fr/xephi/authme/permission/PermissionNode.java deleted file mode 100644 index 189f97b5..00000000 --- a/src/main/java/fr/xephi/authme/permission/PermissionNode.java +++ /dev/null @@ -1,21 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * Common interface for AuthMe permission nodes. - */ -public interface PermissionNode { - - /** - * Return the node of the permission, e.g. "authme.player.unregister". - * - * @return The name of the permission node - */ - String getNode(); - - /** - * Return the default permission for this node, e.g. "OP_ONLY" - * - * @return The default level of permission - */ - DefaultPermission getDefaultPermission(); -} diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java deleted file mode 100644 index 7399d0ca..00000000 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ /dev/null @@ -1,466 +0,0 @@ -package fr.xephi.authme.permission; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.handlers.LuckPermsHandler; -import fr.xephi.authme.permission.handlers.PermissionHandler; -import fr.xephi.authme.permission.handlers.PermissionHandlerException; -import fr.xephi.authme.permission.handlers.PermissionLoadUserException; -import fr.xephi.authme.permission.handlers.PermissionsExHandler; -import fr.xephi.authme.permission.handlers.VaultHandler; -import fr.xephi.authme.permission.handlers.ZPermissionsHandler; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.util.Collection; -import java.util.Collections; -import java.util.UUID; - -/** - * PermissionsManager. - *

- * A permissions manager, to manage and use various permissions systems. - * This manager supports dynamic plugin hooking and various other features. - *

- * Written by Tim Visée. - * - * @author Tim Visée, http://timvisee.com - * @version 0.3 - */ -public class PermissionsManager implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PermissionsManager.class); - private final Server server; - private final PluginManager pluginManager; - private final Settings settings; - - /** - * The permission handler that is currently in use. - * Null if no permission system is hooked. - */ - private PermissionHandler handler = null; - - @Inject - PermissionsManager(Server server, PluginManager pluginManager, Settings settings) { - this.server = server; - this.pluginManager = pluginManager; - this.settings = settings; - } - - /** - * Check if the permissions manager is currently hooked into any of the supported permissions systems. - * - * @return False if there isn't any permissions system used. - */ - public boolean isEnabled() { - return handler != null; - } - - /** - * Setup and hook into the permissions systems. - */ - @PostConstruct - @VisibleForTesting - void setup() { - if (settings.getProperty(PluginSettings.FORCE_VAULT_HOOK)) { - try { - PermissionHandler handler = createPermissionHandler(PermissionsSystemType.VAULT); - if (handler != null) { - // Show a success message and return - this.handler = handler; - logger.info("Hooked into " + PermissionsSystemType.VAULT.getDisplayName() + "!"); - return; - } - } catch (PermissionHandlerException e) { - logger.logException("Failed to create Vault hook (forced):", e); - } - } else { - // Loop through all the available permissions system types - for (PermissionsSystemType type : PermissionsSystemType.values()) { - try { - PermissionHandler handler = createPermissionHandler(type); - if (handler != null) { - // Show a success message and return - this.handler = handler; - logger.info("Hooked into " + type.getDisplayName() + "!"); - return; - } - } catch (Exception ex) { - // An error occurred, show a warning message - logger.logException("Error while hooking into " + type.getDisplayName(), ex); - } - } - } - - // No recognized permissions system found, show a message and return - logger.info("No supported permissions system found! Permissions are disabled!"); - } - - /** - * Creates a permission handler for the provided permission systems if possible. - * - * @param type the permission systems type for which to create a corresponding permission handler - * - * @return the permission handler, or {@code null} if not possible - * - * @throws PermissionHandlerException during initialization of the permission handler - */ - private PermissionHandler createPermissionHandler(PermissionsSystemType type) throws PermissionHandlerException { - // Try to find the plugin for the current permissions system - Plugin plugin = pluginManager.getPlugin(type.getPluginName()); - - if (plugin == null) { - return null; - } - - // Make sure the plugin is enabled before hooking - if (!plugin.isEnabled()) { - logger.info("Not hooking into " + type.getDisplayName() + " because it's disabled!"); - return null; - } - - switch (type) { - case LUCK_PERMS: - return new LuckPermsHandler(); - case PERMISSIONS_EX: - return new PermissionsExHandler(); - case Z_PERMISSIONS: - return new ZPermissionsHandler(); - case VAULT: - return new VaultHandler(server); - default: - throw new IllegalStateException("Unhandled permission type '" + type + "'"); - } - } - - /** - * Break the hook with all permission systems. - */ - private void unhook() { - // Reset the current used permissions system - this.handler = null; - - // Print a status message to the console - logger.info("Unhooked from Permissions!"); - } - - /** - * Reload the permissions manager, and re-hook all permission plugins. - */ - @Override - public void reload() { - // Unhook all permission plugins - unhook(); - - // Set up the permissions manager again - setup(); - } - - /** - * Method called when a plugin is being enabled. - * - * @param pluginName The name of the plugin being enabled. - */ - public void onPluginEnable(String pluginName) { - // Check if any known permissions system is enabling - if (PermissionsSystemType.isPermissionSystem(pluginName)) { - logger.info(pluginName + " plugin enabled, dynamically updating permissions hooks!"); - setup(); - } - } - - /** - * Method called when a plugin is being disabled. - * - * @param pluginName The name of the plugin being disabled. - */ - public void onPluginDisable(String pluginName) { - // Check if any known permission system is being disabled - if (PermissionsSystemType.isPermissionSystem(pluginName)) { - logger.info(pluginName + " plugin disabled, updating hooks!"); - setup(); - } - } - - /** - * Return the permissions system that is hooked into. - * - * @return The permissions system, or null. - */ - public PermissionsSystemType getPermissionSystem() { - return isEnabled() ? handler.getPermissionSystem() : null; - } - - /** - * Check if the command sender has permission for the given permissions node. If no permissions system is used or - * if the sender is not a player (e.g. console user), the player has to be OP in order to have the permission. - * - * @param sender The command sender. - * @param permissionNode The permissions node to verify. - * - * @return True if the sender has the permission, false otherwise. - */ - public boolean hasPermission(CommandSender sender, PermissionNode permissionNode) { - // Check if the permission node is null - if (permissionNode == null) { - return true; - } - - // Return default if sender is not a player or no permission system is in use - if (!(sender instanceof Player) || !isEnabled()) { - return permissionNode.getDefaultPermission().evaluate(sender); - } - - Player player = (Player) sender; - return player.hasPermission(permissionNode.getNode()); - } - - /** - * Check if a player has permission for the given permission node. This is for offline player checks. - * If no permissions system is used, then the player will not have permission. - * - * @param player The offline player - * @param permissionNode The permission node to verify - * - * @return true if the player has permission, false otherwise - */ - public boolean hasPermissionOffline(OfflinePlayer player, PermissionNode permissionNode) { - // Check if the permission node is null - if (permissionNode == null) { - return true; - } - - if (!isEnabled()) { - return permissionNode.getDefaultPermission().evaluate(player); - } - - return handler.hasPermissionOffline(player.getName(), permissionNode); - } - - /** - * Check whether the offline player with the given name has permission for the given permission node. - * This method is used as a last resort when nothing besides the name is known. - * - * @param name The name of the player - * @param permissionNode The permission node to verify - * - * @return true if the player has permission, false otherwise - */ - public boolean hasPermissionOffline(String name, PermissionNode permissionNode) { - if (permissionNode == null) { - return true; - } - if (!isEnabled()) { - return permissionNode.getDefaultPermission().evaluate(null); - } - - return handler.hasPermissionOffline(name, permissionNode); - } - - /** - * Check whether the current permissions system has group support. - * If no permissions system is hooked, false will be returned. - * - * @return True if the current permissions system supports groups, false otherwise. - */ - public boolean hasGroupSupport() { - return isEnabled() && handler.hasGroupSupport(); - } - - /** - * Get the permission groups of a player, if available. - * - * @param player The player. - * - * @return Permission groups, or an empty collection if this feature is not supported. - */ - public Collection getGroups(OfflinePlayer player) { - return isEnabled() ? handler.getGroups(player) : Collections.emptyList(); - } - - /** - * Get the primary group of a player, if available. - * - * @param player The player. - * - * @return The name of the primary permission group. Or null. - */ - public UserGroup getPrimaryGroup(OfflinePlayer player) { - return isEnabled() ? handler.getPrimaryGroup(player) : null; - } - - /** - * Check whether the player is in the specified group. - * - * @param player The player. - * @param groupName The group name. - * - * @return True if the player is in the specified group, false otherwise. - * False is also returned if groups aren't supported by the used permissions system. - */ - public boolean isInGroup(OfflinePlayer player, UserGroup groupName) { - return isEnabled() && handler.isInGroup(player, groupName); - } - - /** - * Add the permission group of a player, if supported. - * - * @param player The player - * @param groupName The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - public boolean addGroup(OfflinePlayer player, UserGroup groupName) { - if (!isEnabled() || StringUtils.isBlank(groupName.getGroupName())) { - return false; - } - return handler.addToGroup(player, groupName); - } - - /** - * Add the permission groups of a player, if supported. - * - * @param player The player - * @param groupNames The name of the groups to add. - * - * @return True if at least one group was added, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - public boolean addGroups(OfflinePlayer player, Collection groupNames) { - // If no permissions system is used, return false - if (!isEnabled()) { - return false; - } - - // Add each group to the user - boolean result = false; - for (UserGroup group : groupNames) { - if (!group.getGroupName().isEmpty()) { - result |= handler.addToGroup(player, group); - } - } - - // Return the result - return result; - } - - /** - * Remove the permission group of a player, if supported. - * - * @param player The player - * @param group The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - public boolean removeGroup(OfflinePlayer player, UserGroup group) { - return isEnabled() && handler.removeFromGroup(player, group); - } - - /** - * Remove the permission groups of a player, if supported. - * - * @param player The player - * @param groupNames The name of the groups to remove. - * - * @return True if at least one group was removed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - public boolean removeGroups(OfflinePlayer player, Collection groupNames) { - // If no permissions system is used, return false - if (!isEnabled()) { - return false; - } - - // Add each group to the user - boolean result = false; - for (UserGroup group : groupNames) { - if (!group.getGroupName().isEmpty()) { - result |= handler.removeFromGroup(player, group); - } - } - - // Return the result - return result; - } - - /** - * Set the permission group of a player, if supported. - * This clears the current groups of the player. - * - * @param player The player - * @param group The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - public boolean setGroup(OfflinePlayer player, UserGroup group) { - return isEnabled() && handler.setGroup(player, group); - } - - /** - * Remove all groups of the specified player, if supported. - * Systems like Essentials GroupManager don't allow all groups to be removed from a player, thus the user will stay - * in its primary group. All the subgroups are removed just fine. - * - * @param player The player to remove all groups from. - * - * @return True if succeed, false otherwise. - * False will also be returned if this feature isn't supported for the used permissions system. - */ - public boolean removeAllGroups(OfflinePlayer player) { - // If no permissions system is used, return false - if (!isEnabled()) { - return false; - } - - // Get a list of current groups - Collection groups = getGroups(player); - - // Remove each group - return removeGroups(player, groups); - } - - /** - * Loads the permission data of the given player. - * - * @param offlinePlayer the offline player. - * @return true if the load was successful. - */ - public boolean loadUserData(OfflinePlayer offlinePlayer) { - try { - loadUserData(offlinePlayer.getUniqueId()); - } catch (PermissionLoadUserException e) { - logger.logException("Unable to load the permission data of user " + offlinePlayer.getName(), e); - return false; - } - return true; - } - - /** - * Loads the permission data of the given player unique identifier. - * - * @param uuid the {@link UUID} of the player. - * @throws PermissionLoadUserException if the action failed. - */ - public void loadUserData(UUID uuid) throws PermissionLoadUserException { - if (!isEnabled()) { - return; - } - handler.loadUserData(uuid); - } - -} diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java b/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java deleted file mode 100644 index 00f01036..00000000 --- a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java +++ /dev/null @@ -1,91 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * Enum representing the permissions systems AuthMe supports. - */ -public enum PermissionsSystemType { - - /** - * LuckPerms. - */ - LUCK_PERMS("LuckPerms", "LuckPerms"), - - /** - * Permissions Ex. - */ - PERMISSIONS_EX("PermissionsEx", "PermissionsEx"), - - /** - * zPermissions. - */ - Z_PERMISSIONS("zPermissions", "zPermissions"), - - /** - * Vault. - */ - VAULT("Vault", "Vault"); - - /** - * The display name of the permissions system. - */ - private String displayName; - - /** - * The name of the permissions system plugin. - */ - private String pluginName; - - /** - * Constructor for PermissionsSystemType. - * - * @param displayName Display name of the permissions system. - * @param pluginName Name of the plugin. - */ - PermissionsSystemType(String displayName, String pluginName) { - this.displayName = displayName; - this.pluginName = pluginName; - } - - /** - * Get the display name of the permissions system. - * - * @return Display name. - */ - public String getDisplayName() { - return this.displayName; - } - - /** - * Return the plugin name. - * - * @return Plugin name. - */ - public String getPluginName() { - return this.pluginName; - } - - /** - * Cast the permissions system type to a string. - * - * @return The display name of the permissions system. - */ - @Override - public String toString() { - return getDisplayName(); - } - - /** - * Check if a given plugin is a permissions system. - * - * @param name The name of the plugin to check. - * @return If the plugin is a valid permissions system. - */ - public static boolean isPermissionSystem(String name) { - for (PermissionsSystemType permissionsSystemType : values()) { - if (permissionsSystemType.pluginName.equals(name)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java deleted file mode 100644 index d7427f46..00000000 --- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java +++ /dev/null @@ -1,112 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * AuthMe player permission nodes, for regular players. - */ -public enum PlayerPermission implements PermissionNode { - - /** - * Command permission to login. - */ - LOGIN("authme.player.login"), - - /** - * Command permission to logout. - */ - LOGOUT("authme.player.logout"), - - /** - * Command permission to register. - */ - REGISTER("authme.player.register"), - - /** - * Command permission to unregister. - */ - UNREGISTER("authme.player.unregister"), - - /** - * Command permission to change the password. - */ - CHANGE_PASSWORD("authme.player.changepassword"), - - /** - * Command permission to see the own email address. - */ - SEE_EMAIL("authme.player.email.see"), - - /** - * Command permission to add an email address. - */ - ADD_EMAIL("authme.player.email.add"), - - /** - * Command permission to change the email address. - */ - CHANGE_EMAIL("authme.player.email.change"), - - /** - * Command permission to recover an account using its email address. - */ - RECOVER_EMAIL("authme.player.email.recover"), - - /** - * Command permission to use captcha. - */ - CAPTCHA("authme.player.captcha"), - - /** - * Permission for users a login can be forced to. - */ - CAN_LOGIN_BE_FORCED("authme.player.canbeforced"), - - /** - * Permission to use to see own other accounts. - */ - SEE_OWN_ACCOUNTS("authme.player.seeownaccounts"), - - /** - * Permission to use the email verification codes feature. - */ - VERIFICATION_CODE("authme.player.security.verificationcode"), - - /** - * Permission that enables on join quick commands checks for the player. - */ - QUICK_COMMANDS_PROTECTION("authme.player.protection.quickcommandsprotection"), - - /** - * Permission to enable two-factor authentication. - */ - ENABLE_TWO_FACTOR_AUTH("authme.player.totpadd"), - - /** - * Permission to disable two-factor authentication. - */ - DISABLE_TWO_FACTOR_AUTH("authme.player.totpremove"); - - /** - * The permission node. - */ - private String node; - - /** - * Constructor. - * - * @param node Permission node. - */ - PlayerPermission(String node) { - this.node = node; - } - - @Override - public String getNode() { - return node; - } - - @Override - public DefaultPermission getDefaultPermission() { - return DefaultPermission.ALLOWED; - } - -} diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java deleted file mode 100644 index b9fe17e7..00000000 --- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.xephi.authme.permission; - -/** - * Permission nodes that give a player a status (e.g. VIP) - * or grant them more freedom (e.g. less restrictions). - */ -public enum PlayerStatePermission implements PermissionNode { - - /** - * Permission node to bypass AntiBot protection. - */ - BYPASS_ANTIBOT("authme.bypassantibot", DefaultPermission.OP_ONLY), - - /** - * Permission node to bypass BungeeCord server teleportation. - */ - BYPASS_BUNGEE_SEND("authme.bypassbungeesend", DefaultPermission.NOT_ALLOWED), - - /** - * Permission for users to bypass force-survival mode. - */ - BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY), - - /** - * When the server is full and someone with this permission joins the server, someone will be kicked. - */ - IS_VIP("authme.vip", DefaultPermission.NOT_ALLOWED), - - /** - * Permission to be able to register multiple accounts. - */ - ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY), - - /** - * Permission to bypass the purging process. - */ - BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED), - - /** - * Permission to bypass the GeoIp country code check. - */ - BYPASS_COUNTRY_CHECK("authme.bypasscountrycheck", DefaultPermission.NOT_ALLOWED), - - /** - * Permission to send chat messages before being logged in. - */ - ALLOW_CHAT_BEFORE_LOGIN("authme.allowchatbeforelogin", DefaultPermission.NOT_ALLOWED); - - /** - * The permission node. - */ - private String node; - - /** - * The default permission level. - */ - private DefaultPermission defaultPermission; - - /** - * Constructor. - * - * @param node Permission node - * @param defaultPermission The default permission - */ - PlayerStatePermission(String node, DefaultPermission defaultPermission) { - this.node = node; - this.defaultPermission = defaultPermission; - } - - @Override - public String getNode() { - return node; - } - - @Override - public DefaultPermission getDefaultPermission() { - return defaultPermission; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermGroup.java b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermGroup.java deleted file mode 100644 index 81a34a4e..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermGroup.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import net.luckperms.api.context.ImmutableContextSet; -import net.luckperms.api.model.group.Group; - -public class LuckPermGroup { - private Group group; - private ImmutableContextSet contexts; - - public LuckPermGroup(Group group, ImmutableContextSet contexts) { - this.group = group; - - this.contexts = contexts; - } - - public Group getGroup() { - return group; - } - - public ImmutableContextSet getContexts() { - return contexts; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java deleted file mode 100644 index 3e786f33..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java +++ /dev/null @@ -1,227 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsSystemType; -import net.luckperms.api.LuckPerms; -import net.luckperms.api.LuckPermsProvider; -import net.luckperms.api.cacheddata.CachedPermissionData; -import net.luckperms.api.context.ContextSetFactory; -import net.luckperms.api.model.data.DataMutateResult; -import net.luckperms.api.model.group.Group; -import net.luckperms.api.model.user.User; -import net.luckperms.api.node.NodeEqualityPredicate; -import net.luckperms.api.node.types.InheritanceNode; -import net.luckperms.api.query.QueryMode; -import net.luckperms.api.query.QueryOptions; -import org.bukkit.OfflinePlayer; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; - -/** - * Handler for LuckPerms. - * - * @see LuckPerms SpigotMC page - * @see LuckPerms on Github - */ -public class LuckPermsHandler implements PermissionHandler { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(LuckPermsHandler.class); - private LuckPerms luckPerms; - - public LuckPermsHandler() throws PermissionHandlerException { - try { - luckPerms = LuckPermsProvider.get(); - } catch (IllegalStateException e) { - throw new PermissionHandlerException("Could not get api of LuckPerms", e); - } - } - - @Override - public boolean addToGroup(OfflinePlayer player, UserGroup group) { - Group newGroup = luckPerms.getGroupManager().getGroup(group.getGroupName()); - if (newGroup == null) { - return false; - } - - String playerName = player.getName(); - if (playerName == null) { - return false; - } - User user = luckPerms.getUserManager().getUser(playerName); - if (user == null) { - return false; - } - - InheritanceNode node = buildGroupNode(group); - - DataMutateResult result = user.data().add(node); - if (result == DataMutateResult.FAIL) { - return false; - } - - luckPerms.getUserManager().saveUser(user); - return true; - } - - @Override - public boolean hasGroupSupport() { - return true; - } - - @Override - public boolean hasPermissionOffline(String name, PermissionNode node) { - User user = luckPerms.getUserManager().getUser(name); - if (user == null) { - logger.warning("LuckPermsHandler: tried to check permission for offline user " - + name + " but it isn't loaded!"); - return false; - } - - CachedPermissionData permissionData = user.getCachedData() - .getPermissionData(QueryOptions.builder(QueryMode.CONTEXTUAL).build()); - return permissionData.checkPermission(node.getNode()).asBoolean(); - } - - @Override - public boolean isInGroup(OfflinePlayer player, UserGroup group) { - String playerName = player.getName(); - if (playerName == null) { - return false; - } - User user = luckPerms.getUserManager().getUser(playerName); - if (user == null) { - logger.warning("LuckPermsHandler: tried to check group for offline user " - + player.getName() + " but it isn't loaded!"); - return false; - } - - InheritanceNode inheritanceNode = InheritanceNode.builder(group.getGroupName()).build(); - return user.data().contains(inheritanceNode, NodeEqualityPredicate.EXACT).asBoolean(); - } - - @Override - public boolean removeFromGroup(OfflinePlayer player, UserGroup group) { - String playerName = player.getName(); - if (playerName == null) { - return false; - } - User user = luckPerms.getUserManager().getUser(playerName); - if (user == null) { - logger.warning("LuckPermsHandler: tried to remove group for offline user " - + player.getName() + " but it isn't loaded!"); - return false; - } - - InheritanceNode groupNode = InheritanceNode.builder(group.getGroupName()).build(); - boolean result = user.data().remove(groupNode) != DataMutateResult.FAIL; - - luckPerms.getUserManager().saveUser(user); - return result; - } - - @Override - public boolean setGroup(OfflinePlayer player, UserGroup group) { - String playerName = player.getName(); - if (playerName == null) { - return false; - } - User user = luckPerms.getUserManager().getUser(playerName); - if (user == null) { - logger.warning("LuckPermsHandler: tried to set group for offline user " - + player.getName() + " but it isn't loaded!"); - return false; - } - - InheritanceNode groupNode = buildGroupNode(group); - - DataMutateResult result = user.data().add(groupNode); - if (result == DataMutateResult.FAIL) { - return false; - } - user.data().clear(node -> { - if (!(node instanceof InheritanceNode)) { - return false; - } - InheritanceNode inheritanceNode = (InheritanceNode) node; - return !inheritanceNode.equals(groupNode); - }); - - luckPerms.getUserManager().saveUser(user); - return true; - } - - @Override - public List getGroups(OfflinePlayer player) { - String playerName = player.getName(); - if (playerName == null) { - return Collections.emptyList(); - } - User user = luckPerms.getUserManager().getUser(playerName); - if (user == null) { - logger.warning("LuckPermsHandler: tried to get groups for offline user " - + player.getName() + " but it isn't loaded!"); - return Collections.emptyList(); - } - - return user.getDistinctNodes().stream() - .filter(node -> node instanceof InheritanceNode) - .map(node -> (InheritanceNode) node) - .map(node -> { - Group group = luckPerms.getGroupManager().getGroup(node.getGroupName()); - if (group == null) { - return null; - } - return new LuckPermGroup(group, node.getContexts()); - }) - .filter(Objects::nonNull) - .sorted((o1, o2) -> sortGroups(user, o1, o2)) - .map(g -> new UserGroup(g.getGroup().getName(), g.getContexts().toFlattenedMap())) - .collect(Collectors.toList()); - } - - @Override - public PermissionsSystemType getPermissionSystem() { - return PermissionsSystemType.LUCK_PERMS; - } - - @Override - public void loadUserData(UUID uuid) throws PermissionLoadUserException { - try { - luckPerms.getUserManager().loadUser(uuid).get(5, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new PermissionLoadUserException("Unable to load the permission data of the user " + uuid, e); - } - } - - @NotNull - private InheritanceNode buildGroupNode(UserGroup group) { - ContextSetFactory contextSetFactory = luckPerms.getContextManager().getContextSetFactory(); - InheritanceNode.Builder builder = InheritanceNode.builder(group.getGroupName()); - if (group.getContextMap() != null) { - group.getContextMap().forEach((k, v) -> builder.withContext((contextSetFactory.immutableOf(k, v)))); - } - return builder.build(); - } - - private int sortGroups(User user, LuckPermGroup o1, LuckPermGroup o2) { - Group group1 = o1.getGroup(); - Group group2 = o2.getGroup(); - if (group1.getName().equals(user.getPrimaryGroup()) || group2.getName().equals(user.getPrimaryGroup())) { - return group1.getName().equals(user.getPrimaryGroup()) ? 1 : -1; - } - - int i = Integer.compare(group2.getWeight().orElse(0), group1.getWeight().orElse(0)); - return i != 0 ? i : group1.getName().compareToIgnoreCase(group2.getName()); - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java deleted file mode 100644 index efdc989e..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandler.java +++ /dev/null @@ -1,114 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsSystemType; -import fr.xephi.authme.util.Utils; -import org.bukkit.OfflinePlayer; - -import java.util.Collection; -import java.util.UUID; - -public interface PermissionHandler { - - /** - * Add the permission group of a player, if supported. - * - * @param player The player - * @param group The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - boolean addToGroup(OfflinePlayer player, UserGroup group); - - /** - * Check whether the current permissions system has group support. - * If no permissions system is hooked, false will be returned. - * - * @return True if the current permissions system supports groups, false otherwise. - */ - boolean hasGroupSupport(); - - /** - * Check if a player has permission by their name. - * Used to check an offline player's permission. - * - * @param name The player's name. - * @param node The permission node. - * - * @return True if the player has permission. - */ - boolean hasPermissionOffline(String name, PermissionNode node); - - /** - * Check whether the player is in the specified group. - * - * @param player The player. - * @param group The group name. - * - * @return True if the player is in the specified group, false otherwise. - * False is also returned if groups aren't supported by the used permissions system. - */ - default boolean isInGroup(OfflinePlayer player, UserGroup group) { - return getGroups(player).contains(group); - } - - /** - * Remove the permission group of a player, if supported. - * - * @param player The player - * @param group The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - boolean removeFromGroup(OfflinePlayer player, UserGroup group); - - /** - * Set the permission group of a player, if supported. - * This clears the current groups of the player. - * - * @param player The player - * @param group The name of the group. - * - * @return True if succeed, false otherwise. - * False is also returned if this feature isn't supported for the current permissions system. - */ - boolean setGroup(OfflinePlayer player, UserGroup group); - - /** - * Get the permission groups of a player, if available. - * - * @param player The player. - * - * @return Permission groups, or an empty list if this feature is not supported. - */ - Collection getGroups(OfflinePlayer player); - - /** - * Get the primary group of a player, if available. - * - * @param player The player. - * - * @return The name of the primary permission group. Or null. - */ - default UserGroup getPrimaryGroup(OfflinePlayer player) { - Collection groups = getGroups(player); - if (Utils.isCollectionEmpty(groups)) { - return null; - } - return groups.iterator().next(); - } - - /** - * Get the permission system that is being used. - * - * @return The permission system. - */ - PermissionsSystemType getPermissionSystem(); - - default void loadUserData(UUID uuid) throws PermissionLoadUserException { - } - -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java deleted file mode 100644 index a0de9ada..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionHandlerException.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -/** - * Exception during the instantiation of a {@link PermissionHandler}. - */ -@SuppressWarnings("serial") -public class PermissionHandlerException extends Exception { - - public PermissionHandlerException(String message) { - super(message); - } - - public PermissionHandlerException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionLoadUserException.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionLoadUserException.java deleted file mode 100644 index 697b4918..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionLoadUserException.java +++ /dev/null @@ -1,13 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import java.util.UUID; - -/** - * Exception thrown when a {@link PermissionHandler#loadUserData(UUID uuid)} request fails. - */ -public class PermissionLoadUserException extends Exception { - - public PermissionLoadUserException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java deleted file mode 100644 index db834ca4..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsSystemType; -import org.bukkit.OfflinePlayer; -import ru.tehkode.permissions.PermissionManager; -import ru.tehkode.permissions.PermissionUser; -import ru.tehkode.permissions.bukkit.PermissionsEx; - -import java.util.ArrayList; -import java.util.List; - -import static java.util.stream.Collectors.toList; - -/** - * Handler for PermissionsEx. - * - * @see PermissionsEx Bukkit page - * @see PermissionsEx on Github - */ -public class PermissionsExHandler implements PermissionHandler { - - private PermissionManager permissionManager; - - public PermissionsExHandler() throws PermissionHandlerException { - permissionManager = PermissionsEx.getPermissionManager(); - if (permissionManager == null) { - throw new PermissionHandlerException("Could not get manager of PermissionsEx"); - } - } - - @Override - public boolean addToGroup(OfflinePlayer player, UserGroup group) { - if (!PermissionsEx.getPermissionManager().getGroupNames().contains(group)) { - return false; - } - - PermissionUser user = PermissionsEx.getUser(player.getName()); - user.addGroup(group.getGroupName()); - return true; - } - - @Override - public boolean hasGroupSupport() { - return true; - } - - @Override - public boolean hasPermissionOffline(String name, PermissionNode node) { - PermissionUser user = permissionManager.getUser(name); - return user.has(node.getNode()); - } - - @Override - public boolean isInGroup(OfflinePlayer player, UserGroup group) { - PermissionUser user = permissionManager.getUser(player.getName()); - return user.inGroup(group.getGroupName()); - } - - @Override - public boolean removeFromGroup(OfflinePlayer player, UserGroup group) { - PermissionUser user = permissionManager.getUser(player.getName()); - user.removeGroup(group.getGroupName()); - return true; - } - - @Override - public boolean setGroup(OfflinePlayer player, UserGroup group) { - List groups = new ArrayList<>(); - groups.add(group.getGroupName()); - - PermissionUser user = permissionManager.getUser(player.getName()); - user.setParentsIdentifier(groups); - return true; - } - - @Override - public List getGroups(OfflinePlayer player) { - PermissionUser user = permissionManager.getUser(player.getName()); - return user.getParentIdentifiers(null).stream() - .map(i -> new UserGroup(i, null)) - .collect(toList()); - } - - @Override - public PermissionsSystemType getPermissionSystem() { - return PermissionsSystemType.PERMISSIONS_EX; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java deleted file mode 100644 index 87f5fc27..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/VaultHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsSystemType; -import net.milkbowl.vault.permission.Permission; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.plugin.RegisteredServiceProvider; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static java.util.stream.Collectors.toList; - -/** - * Handler for permissions via Vault. - * - * @see Vault Bukkit page - * @see Vault on Github - */ -public class VaultHandler implements PermissionHandler { - - private Permission vaultProvider; - - public VaultHandler(Server server) throws PermissionHandlerException { - this.vaultProvider = getVaultPermission(server); - } - - /** - * Returns the Vault Permission interface. - * - * @param server the bukkit server instance - * @return the vault permission instance - * @throws PermissionHandlerException if the vault permission instance cannot be retrieved - */ - @VisibleForTesting - Permission getVaultPermission(Server server) throws PermissionHandlerException { - // Get the permissions provider service - RegisteredServiceProvider permissionProvider = server - .getServicesManager().getRegistration(Permission.class); - if (permissionProvider == null) { - throw new PermissionHandlerException("Could not load permissions provider service"); - } - - // Get the Vault provider and make sure it's valid - Permission vaultPerms = permissionProvider.getProvider(); - if (vaultPerms == null) { - throw new PermissionHandlerException("Could not load Vault permissions provider"); - } - return vaultPerms; - } - - @Override - public boolean addToGroup(OfflinePlayer player, UserGroup group) { - return vaultProvider.playerAddGroup(null, player, group.getGroupName()); - } - - @Override - public boolean hasGroupSupport() { - return vaultProvider.hasGroupSupport(); - } - - @Override - public boolean hasPermissionOffline(String name, PermissionNode node) { - return vaultProvider.has((String) null, name, node.getNode()); - } - - @Override - public boolean isInGroup(OfflinePlayer player, UserGroup group) { - return vaultProvider.playerInGroup(null, player, group.getGroupName()); - } - - @Override - public boolean removeFromGroup(OfflinePlayer player, UserGroup group) { - return vaultProvider.playerRemoveGroup(null, player, group.getGroupName()); - } - - @Override - public boolean setGroup(OfflinePlayer player, UserGroup group) { - for (UserGroup g : getGroups(player)) { - removeFromGroup(player, g); - } - - return vaultProvider.playerAddGroup(null, player, group.getGroupName()); - } - - @Override - public List getGroups(OfflinePlayer player) { - String[] groups = vaultProvider.getPlayerGroups(null, player); - return groups == null ? Collections.emptyList() : Arrays.stream(groups).map(UserGroup::new).collect(toList()); - } - - @Override - public UserGroup getPrimaryGroup(OfflinePlayer player) { - return new UserGroup(vaultProvider.getPrimaryGroup(null, player)); - } - - @Override - public PermissionsSystemType getPermissionSystem() { - return PermissionsSystemType.VAULT; - } -} diff --git a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java deleted file mode 100644 index 0b632de6..00000000 --- a/src/main/java/fr/xephi/authme/permission/handlers/ZPermissionsHandler.java +++ /dev/null @@ -1,79 +0,0 @@ -package fr.xephi.authme.permission.handlers; - -import fr.xephi.authme.data.limbo.UserGroup; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsSystemType; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; - -import java.util.Collection; -import java.util.Map; - -import static java.util.stream.Collectors.toList; - -/** - * Handler for zPermissions. - * - * @see zPermissions Bukkit page - * @see zPermissions on Github - */ -public class ZPermissionsHandler implements PermissionHandler { - - private ZPermissionsService zPermissionsService; - - public ZPermissionsHandler() throws PermissionHandlerException { - // Set the zPermissions service and make sure it's valid - ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class); - if (zPermissionsService == null) { - throw new PermissionHandlerException("Failed to get the ZPermissions service!"); - } - this.zPermissionsService = zPermissionsService; - } - - @Override - public boolean addToGroup(OfflinePlayer player, UserGroup group) { - return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - "permissions player " + player.getName() + " addgroup " + group.getGroupName()); - } - - @Override - public boolean hasGroupSupport() { - return true; - } - - @Override - public boolean hasPermissionOffline(String name, PermissionNode node) { - Map perms = zPermissionsService.getPlayerPermissions(null, null, name); - return perms.getOrDefault(node.getNode(), false); - } - - @Override - public boolean removeFromGroup(OfflinePlayer player, UserGroup group) { - return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - "permissions player " + player.getName() + " removegroup " + group.getGroupName()); - } - - @Override - public boolean setGroup(OfflinePlayer player, UserGroup group) { - return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - "permissions player " + player.getName() + " setgroup " + group.getGroupName()); - } - - @Override - public Collection getGroups(OfflinePlayer player) { - return zPermissionsService.getPlayerGroups(player.getName()).stream() - .map(UserGroup::new) - .collect(toList()); - } - - @Override - public UserGroup getPrimaryGroup(OfflinePlayer player) { - return new UserGroup(zPermissionsService.getPlayerPrimaryGroup(player.getName())); - } - - @Override - public PermissionsSystemType getPermissionSystem() { - return PermissionsSystemType.Z_PERMISSIONS; - } -} diff --git a/src/main/java/fr/xephi/authme/process/AsynchronousProcess.java b/src/main/java/fr/xephi/authme/process/AsynchronousProcess.java deleted file mode 100644 index 80c06313..00000000 --- a/src/main/java/fr/xephi/authme/process/AsynchronousProcess.java +++ /dev/null @@ -1,10 +0,0 @@ -package fr.xephi.authme.process; - -/** - * Marker interface for asynchronous AuthMe processes. - *

- * These processes handle intensive (I/O or otherwise) actions and are - * therefore scheduled to run asynchronously. - */ -public interface AsynchronousProcess { -} diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java deleted file mode 100644 index 454c0c18..00000000 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ /dev/null @@ -1,107 +0,0 @@ -package fr.xephi.authme.process; - -import fr.xephi.authme.process.changepassword.AsyncChangePassword; -import fr.xephi.authme.process.email.AsyncAddEmail; -import fr.xephi.authme.process.email.AsyncChangeEmail; -import fr.xephi.authme.process.join.AsynchronousJoin; -import fr.xephi.authme.process.login.AsynchronousLogin; -import fr.xephi.authme.process.logout.AsynchronousLogout; -import fr.xephi.authme.process.quit.AsynchronousQuit; -import fr.xephi.authme.process.register.AsyncRegister; -import fr.xephi.authme.process.register.executors.RegistrationMethod; -import fr.xephi.authme.process.register.executors.RegistrationParameters; -import fr.xephi.authme.process.unregister.AsynchronousUnregister; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Performs auth actions, e.g. when a player joins, registers or wants to change his password. - */ -public class Management { - - @Inject - private BukkitService bukkitService; - - // Processes - @Inject - private AsyncAddEmail asyncAddEmail; - @Inject - private AsyncChangeEmail asyncChangeEmail; - @Inject - private AsynchronousLogout asynchronousLogout; - @Inject - private AsynchronousQuit asynchronousQuit; - @Inject - private AsynchronousJoin asynchronousJoin; - @Inject - private AsyncRegister asyncRegister; - @Inject - private AsynchronousLogin asynchronousLogin; - @Inject - private AsynchronousUnregister asynchronousUnregister; - @Inject - private AsyncChangePassword asyncChangePassword; - - Management() { - } - - - public void performLogin(Player player, String password) { - runTask(() -> asynchronousLogin.login(player, password)); - } - - public void forceLogin(Player player) { - runTask(() -> asynchronousLogin.forceLogin(player)); - } - - public void forceLogin(Player player, boolean quiet) { - runTask(() -> asynchronousLogin.forceLogin(player, quiet)); - } - - public void performLogout(Player player) { - runTask(() -> asynchronousLogout.logout(player)); - } - - public

void performRegister(RegistrationMethod

variant, P parameters) { - runTask(() -> asyncRegister.register(variant, parameters)); - } - - public void performUnregister(Player player, String password) { - runTask(() -> asynchronousUnregister.unregister(player, password)); - } - - public void performUnregisterByAdmin(CommandSender initiator, String name, Player player) { - runTask(() -> asynchronousUnregister.adminUnregister(initiator, name, player)); - } - - public void performJoin(Player player) { - runTask(() -> asynchronousJoin.processJoin(player)); - } - - public void performQuit(Player player) { - runTask(() -> asynchronousQuit.processQuit(player)); - } - - public void performAddEmail(Player player, String newEmail) { - runTask(() -> asyncAddEmail.addEmail(player, newEmail)); - } - - public void performChangeEmail(Player player, String oldEmail, String newEmail) { - runTask(() -> asyncChangeEmail.changeEmail(player, oldEmail, newEmail)); - } - - public void performPasswordChange(Player player, String oldPassword, String newPassword) { - runTask(() -> asyncChangePassword.changePassword(player, oldPassword, newPassword)); - } - - public void performPasswordChangeAsAdmin(CommandSender sender, String playerName, String newPassword) { - runTask(() -> asyncChangePassword.changePasswordAsAdmin(sender, playerName, newPassword)); - } - - private void runTask(Runnable runnable) { - bukkitService.runTaskOptionallyAsync(runnable); - } -} diff --git a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java deleted file mode 100644 index 0fdfdde3..00000000 --- a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.xephi.authme.process; - -import fr.xephi.authme.process.login.ProcessSyncPlayerLogin; -import fr.xephi.authme.process.logout.ProcessSyncPlayerLogout; -import fr.xephi.authme.process.quit.ProcessSyncPlayerQuit; -import fr.xephi.authme.process.register.ProcessSyncEmailRegister; -import fr.xephi.authme.process.register.ProcessSyncPasswordRegister; -import fr.xephi.authme.service.BukkitService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; - -/** - * Manager for scheduling synchronous processes internally from the asynchronous processes. - * These synchronous processes are a continuation of the associated async processes; they only - * contain certain tasks which may only be run synchronously (most interactions with Bukkit). - * These synchronous tasks should never be called aside from the asynchronous processes. - * - * @see Management - */ -public class SyncProcessManager { - - @Inject - private BukkitService bukkitService; - - @Inject - private ProcessSyncEmailRegister processSyncEmailRegister; - @Inject - private ProcessSyncPasswordRegister processSyncPasswordRegister; - @Inject - private ProcessSyncPlayerLogin processSyncPlayerLogin; - @Inject - private ProcessSyncPlayerLogout processSyncPlayerLogout; - @Inject - private ProcessSyncPlayerQuit processSyncPlayerQuit; - - - public void processSyncEmailRegister(Player player) { - runTask(() -> processSyncEmailRegister.processEmailRegister(player)); - } - - public void processSyncPasswordRegister(Player player) { - runTask(() -> processSyncPasswordRegister.processPasswordRegister(player)); - } - - public void processSyncPlayerLogout(Player player) { - runTask(() -> processSyncPlayerLogout.processSyncLogout(player)); - } - - public void processSyncPlayerLogin(Player player, boolean isFirstLogin, List authsWithSameIp) { - runTask(() -> processSyncPlayerLogin.processPlayerLogin(player, isFirstLogin, authsWithSameIp)); - } - - public void processSyncPlayerQuit(Player player, boolean wasLoggedIn) { - runTask(() -> processSyncPlayerQuit.processSyncQuit(player, wasLoggedIn)); - } - - private void runTask(Runnable runnable) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(runnable); - } -} diff --git a/src/main/java/fr/xephi/authme/process/SynchronousProcess.java b/src/main/java/fr/xephi/authme/process/SynchronousProcess.java deleted file mode 100644 index 6c23a0f8..00000000 --- a/src/main/java/fr/xephi/authme/process/SynchronousProcess.java +++ /dev/null @@ -1,10 +0,0 @@ -package fr.xephi.authme.process; - -/** - * Marker interface for synchronous processes. - *

- * Such processes are scheduled by {@link AsynchronousProcess asynchronous tasks} to perform tasks - * which are required to be executed synchronously (e.g. interactions with the Bukkit API). - */ -public interface SynchronousProcess { -} diff --git a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java b/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java deleted file mode 100644 index aa45d228..00000000 --- a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java +++ /dev/null @@ -1,102 +0,0 @@ -package fr.xephi.authme.process.changepassword; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.CommonService; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -public class AsyncChangePassword implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncChangePassword.class); - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private PlayerCache playerCache; - - AsyncChangePassword() { - } - - /** - * Change password for an online player - * - * @param player the player - * @param oldPassword the old password used by the player - * @param newPassword the new password chosen by the player - */ - public void changePassword(Player player, String oldPassword, String newPassword) { - String name = player.getName().toLowerCase(Locale.ROOT); - PlayerAuth auth = playerCache.getAuth(name); - if (passwordSecurity.comparePassword(oldPassword, auth.getPassword(), player.getName())) { - HashedPassword hashedPassword = passwordSecurity.computeHash(newPassword, name); - auth.setPassword(hashedPassword); - - if (!dataSource.updatePassword(auth)) { - commonService.send(player, MessageKey.ERROR); - return; - } - - // TODO: send an update when a messaging service will be implemented (PASSWORD_CHANGED) - - playerCache.updatePlayer(auth); - commonService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS); - logger.info(player.getName() + " changed his password"); - } else { - commonService.send(player, MessageKey.WRONG_PASSWORD); - } - } - - /** - * Change a user's password as an administrator, without asking for the previous one - * - * @param sender who is performing the operation, null if called by other plugins - * @param playerName the player name - * @param newPassword the new password chosen for the player - */ - public void changePasswordAsAdmin(CommandSender sender, String playerName, String newPassword) { - String lowerCaseName = playerName.toLowerCase(Locale.ROOT); - if (!(playerCache.isAuthenticated(lowerCaseName) || dataSource.isAuthAvailable(lowerCaseName))) { - if (sender == null) { - logger.warning("Tried to change password for user " + lowerCaseName + " but it doesn't exist!"); - } else { - commonService.send(sender, MessageKey.UNKNOWN_USER); - } - return; - } - - HashedPassword hashedPassword = passwordSecurity.computeHash(newPassword, lowerCaseName); - if (dataSource.updatePassword(lowerCaseName, hashedPassword)) { - // TODO: send an update when a messaging service will be implemented (PASSWORD_CHANGED) - - if (sender != null) { - commonService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); - logger.info(sender.getName() + " changed password of " + lowerCaseName); - } else { - logger.info("Changed password of " + lowerCaseName); - } - } else { - if (sender != null) { - commonService.send(sender, MessageKey.ERROR); - } - logger.warning("An error occurred while changing password for user " + lowerCaseName + "!"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java deleted file mode 100644 index 4001420c..00000000 --- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java +++ /dev/null @@ -1,95 +0,0 @@ -package fr.xephi.authme.process.email; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.EmailChangedEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.util.Utils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -/** - * Async task to add an email to an account. - */ -public class AsyncAddEmail implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncAddEmail.class); - - @Inject - private CommonService service; - - @Inject - private DataSource dataSource; - - @Inject - private PlayerCache playerCache; - - @Inject - private ValidationService validationService; - - @Inject - private BukkitService bukkitService; - - AsyncAddEmail() { - } - - /** - * Handles the request to add the given email to the player's account. - * - * @param player the player to add the email to - * @param email the email to add - */ - public void addEmail(Player player, String email) { - String playerName = player.getName().toLowerCase(Locale.ROOT); - - if (playerCache.isAuthenticated(playerName)) { - PlayerAuth auth = playerCache.getAuth(playerName); - String currentEmail = auth.getEmail(); - - if (!Utils.isEmailEmpty(currentEmail)) { - service.send(player, MessageKey.USAGE_CHANGE_EMAIL); - } else if (!validationService.validateEmail(email)) { - service.send(player, MessageKey.INVALID_EMAIL); - } else if (!validationService.isEmailFreeForRegistration(email, player)) { - service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); - } else { - EmailChangedEvent event = bukkitService.createAndCallEvent(isAsync - -> new EmailChangedEvent(player, null, email, isAsync)); - if (event.isCancelled()) { - logger.info("Could not add email to player '" + player + "' – event was cancelled"); - service.send(player, MessageKey.EMAIL_ADD_NOT_ALLOWED); - return; - } - auth.setEmail(email); - if (dataSource.updateEmail(auth)) { - playerCache.updatePlayer(auth); - // TODO: send an update when a messaging service will be implemented (ADD_MAIL) - service.send(player, MessageKey.EMAIL_ADDED_SUCCESS); - } else { - logger.warning("Could not save email for player '" + player + "'"); - service.send(player, MessageKey.ERROR); - } - } - } else { - sendUnloggedMessage(player); - } - } - - private void sendUnloggedMessage(Player player) { - if (dataSource.isAuthAvailable(player.getName())) { - service.send(player, MessageKey.LOGIN_MESSAGE); - } else { - service.send(player, MessageKey.REGISTER_MESSAGE); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java deleted file mode 100644 index 74d9c39b..00000000 --- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java +++ /dev/null @@ -1,107 +0,0 @@ -package fr.xephi.authme.process.email; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.EmailChangedEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -/** - * Async task for changing the email. - */ -public class AsyncChangeEmail implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncChangeEmail.class); - - @Inject - private CommonService service; - - @Inject - private PlayerCache playerCache; - - @Inject - private DataSource dataSource; - - @Inject - private ValidationService validationService; - - @Inject - private BukkitService bukkitService; - - AsyncChangeEmail() { - } - - /** - * Handles the request to change the player's email address. - * - * @param player the player to change the email for - * @param oldEmail provided old email - * @param newEmail provided new email - */ - public void changeEmail(Player player, String oldEmail, String newEmail) { - String playerName = player.getName().toLowerCase(Locale.ROOT); - if (playerCache.isAuthenticated(playerName)) { - PlayerAuth auth = playerCache.getAuth(playerName); - String currentEmail = auth.getEmail(); - - if (currentEmail == null) { - service.send(player, MessageKey.USAGE_ADD_EMAIL); - } else if (newEmail == null || !validationService.validateEmail(newEmail)) { - service.send(player, MessageKey.INVALID_NEW_EMAIL); - } else if (!oldEmail.equalsIgnoreCase(currentEmail)) { - service.send(player, MessageKey.INVALID_OLD_EMAIL); - } else if (!validationService.isEmailFreeForRegistration(newEmail, player)) { - service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR); - } else { - saveNewEmail(auth, player, oldEmail, newEmail); - } - } else { - outputUnloggedMessage(player); - } - } - - /** - * Saves the new email value into the database and informs services. - * - * @param auth the player auth object - * @param player the player object - * @param oldEmail the old email value - * @param newEmail the new email value - */ - private void saveNewEmail(PlayerAuth auth, Player player, String oldEmail, String newEmail) { - EmailChangedEvent event = bukkitService.createAndCallEvent(isAsync - -> new EmailChangedEvent(player, oldEmail, newEmail, isAsync)); - if (event.isCancelled()) { - logger.info("Could not change email for player '" + player + "' – event was cancelled"); - service.send(player, MessageKey.EMAIL_CHANGE_NOT_ALLOWED); - return; - } - - auth.setEmail(newEmail); - if (dataSource.updateEmail(auth)) { - playerCache.updatePlayer(auth); - // TODO: send an update when a messaging service will be implemented (CHANGE_MAIL) - service.send(player, MessageKey.EMAIL_CHANGED_SUCCESS); - } else { - service.send(player, MessageKey.ERROR); - } - } - - private void outputUnloggedMessage(Player player) { - if (dataSource.isAuthAvailable(player.getName())) { - service.send(player, MessageKey.LOGIN_MESSAGE); - } else { - service.send(player, MessageKey.REGISTER_MESSAGE); - } - } -} diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java deleted file mode 100644 index 424c4989..00000000 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ /dev/null @@ -1,246 +0,0 @@ -package fr.xephi.authme.process.join; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.ProxySessionManager; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.ProtectInventoryEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.process.login.AsynchronousLogin; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.PluginHookService; -import fr.xephi.authme.service.SessionService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.bungeecord.MessageType; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.InternetProtocolUtils; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.GameMode; -import org.bukkit.Server; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND; -import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; - -/** - * Asynchronous process for when a player joins. - */ -public class AsynchronousJoin implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousJoin.class); - - @Inject - private Server server; - - @Inject - private Settings settings; - - @Inject - private DataSource database; - - @Inject - private CommonService service; - - @Inject - private LimboService limboService; - - @Inject - private PluginHookService pluginHookService; - - @Inject - private BukkitService bukkitService; - - @Inject - private AsynchronousLogin asynchronousLogin; - - @Inject - private CommandManager commandManager; - - @Inject - private ValidationService validationService; - - @Inject - private SessionService sessionService; - - @Inject - private BungeeSender bungeeSender; - - @Inject - private VelocitySender velocitySender; - - @Inject - private ProxySessionManager proxySessionManager; - - AsynchronousJoin() { - } - - /** - * Processes the given player that has just joined. - * - * @param player the player to process - */ - public void processJoin(Player player) { - String name = player.getName().toLowerCase(Locale.ROOT); - String ip = PlayerUtils.getPlayerIp(player); - - if (!validationService.fulfillsNameRestrictions(player)) { - handlePlayerWithUnmetNameRestriction(player, ip); - return; - } - - if (service.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name)) { - return; - } - - if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE) - && player.getGameMode() != GameMode.SURVIVAL - && !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> player.setGameMode(GameMode.SURVIVAL)); - } - - if (service.getProperty(HooksSettings.DISABLE_SOCIAL_SPY)) { - pluginHookService.setEssentialsSocialSpyStatus(player, false); - } - - if (!validatePlayerCountForIp(player, ip)) { - return; - } - - boolean isAuthAvailable = database.isAuthAvailable(name); - - if (isAuthAvailable) { - // Protect inventory - if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { - ProtectInventoryEvent ev = bukkitService.createAndCallEvent( - isAsync -> new ProtectInventoryEvent(player, isAsync)); - if (ev.isCancelled()) { - player.updateInventory(); - logger.fine("ProtectInventoryEvent has been cancelled for " + player.getName() + "..."); - } - } - - // Session logic - if (sessionService.canResumeSession(player)) { - if (velocitySender.isEnabled()) { - bukkitService.scheduleSyncDelayedTask(() -> - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.LOGIN), service.getProperty(HooksSettings.PROXY_SEND_DELAY)); - } - service.send(player, MessageKey.SESSION_RECONNECTION); - // Run commands - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask( - () -> commandManager.runCommandsOnSessionLogin(player)); - bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player)); - return; - } else if (proxySessionManager.shouldResumeSession(name)) { - service.send(player, MessageKey.SESSION_RECONNECTION); - // Run commands - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask( - () -> commandManager.runCommandsOnSessionLogin(player)); - bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player)); - logger.info("The user " + player.getName() + " has been automatically logged in, " - + "as present in autologin queue."); - return; - } - } else if (!service.getProperty(RegistrationSettings.FORCE)) { - - // Skip if registration is optional - - if (bungeeSender.isEnabled()) { - // As described at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ - // "Keep in mind that you can't send plugin messages directly after a player joins." - bukkitService.scheduleSyncDelayedTask(() -> - bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGIN), settings.getProperty(HooksSettings.PROXY_SEND_DELAY)); - } - if (velocitySender.isEnabled()) { - bukkitService.scheduleSyncDelayedTask(() -> - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.LOGIN), settings.getProperty(HooksSettings.PROXY_SEND_DELAY)); - } - return; - } - - processJoinSync(player, isAuthAvailable); - } - - private void handlePlayerWithUnmetNameRestriction(Player player, String ip) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> { - player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.NOT_OWNER_ERROR)); - if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) { - server.banIP(ip); - } - }); - } - - /** - * Performs various operations in sync mode for an unauthenticated player (such as blindness effect and - * limbo player creation). - * - * @param player the player to process - * @param isAuthAvailable true if the player is registered, false otherwise - */ - private void processJoinSync(Player player, boolean isAuthAvailable) { - int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; - - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> { - limboService.createLimboPlayer(player, isAuthAvailable); - - player.setNoDamageTicks(registrationTimeout); - if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { - player.performCommand("motd"); - } - if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - // Allow infinite blindness effect - int blindTimeOut = (registrationTimeout <= 0) ? 99999 : registrationTimeout; - - // AuthMeReReloaded - Fix potion apply on Folia - bukkitService.runTaskIfFolia(player, () -> player.addPotionEffect(bukkitService.createBlindnessEffect(blindTimeOut))); - } - commandManager.runCommandsOnJoin(player); - }); - } - - /** - * Checks whether the maximum number of accounts has been exceeded for the given IP address (according to - * settings and permissions). If this is the case, the player is kicked. - * - * @param player the player to verify - * @param ip the ip address of the player - * - * @return true if the verification is OK (no infraction), false if player has been kicked - */ - private boolean validatePlayerCountForIp(Player player, String ip) { - if (service.getProperty(RestrictionSettings.MAX_JOIN_PER_IP) > 0 - && !service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) - && !InternetProtocolUtils.isLoopbackAddress(ip) - && countOnlinePlayersByIp(ip) > service.getProperty(RestrictionSettings.MAX_JOIN_PER_IP)) { - - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask( - () -> player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.SAME_IP_ONLINE))); - return false; - } - return true; - } - - private int countOnlinePlayersByIp(String ip) { - int count = 0; - for (Player player : bukkitService.getOnlinePlayers()) { - if (ip.equalsIgnoreCase(PlayerUtils.getPlayerIp(player))) { - ++count; - } - } - return count; - } -} diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java deleted file mode 100644 index 988124d9..00000000 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ /dev/null @@ -1,395 +0,0 @@ -package fr.xephi.authme.process.login; - -import com.google.common.annotations.VisibleForTesting; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.TempbanManager; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.captcha.LoginCaptchaManager; -import fr.xephi.authme.data.limbo.LimboMessageType; -import fr.xephi.authme.data.limbo.LimboPlayerState; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; -import fr.xephi.authme.events.FailedLoginEvent; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.AdminPermission; -import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.SessionService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.bungeecord.MessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.InternetProtocolUtils; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.Utils; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** - * Asynchronous task for a player login. - */ -public class AsynchronousLogin implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousLogin.class); - - @Inject - private DataSource dataSource; - - @Inject - private CommonService service; - - @Inject - private PlayerCache playerCache; - - @Inject - private SyncProcessManager syncProcessManager; - - @Inject - private BukkitService bukkitService; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private LoginCaptchaManager loginCaptchaManager; - - @Inject - private TempbanManager tempbanManager; - - @Inject - private LimboService limboService; - - @Inject - private EmailService emailService; - - @Inject - private SessionService sessionService; - @Inject - private Settings settings; - @Inject - private BungeeSender bungeeSender; - @Inject - private VelocitySender velocitySender; - - AsynchronousLogin() { - } - - /** - * Processes a player's login request. - * - * @param player the player to log in - * @param password the password to log in with - */ - public void login(Player player, String password) { - PlayerAuth auth = getPlayerAuth(player); - if (auth != null && checkPlayerInfo(player, auth, password)) { - if (auth.getTotpKey() != null) { - limboService.resetMessageTask(player, LimboMessageType.TOTP_CODE); - limboService.getLimboPlayer(player.getName()).setState(LimboPlayerState.TOTP_REQUIRED); - // TODO #1141: Check if we should check limbo state before processing password - } else { - performLogin(player, auth); - } - } - } - - /** - * Logs a player in without requiring a password. - * - * @param player the player to log in - */ - public synchronized void forceLogin(Player player) { - PlayerAuth auth = getPlayerAuth(player); - if (auth != null) { - performLogin(player, auth); - } - } - - /** - * Logs a player in without requiring a password. - * - * @param player the player to log in - * @param quiet if true no messages will be sent - */ - public void forceLogin(Player player, boolean quiet) { - PlayerAuth auth = getPlayerAuth(player, quiet); - if (auth != null) { - performLogin(player, auth); - } - } - - /** - * Checks the precondition for authentication (like user known) and returns - * the player's {@link PlayerAuth} object. - * - * @param player the player to check - * @return the PlayerAuth object, or {@code null} if the player doesn't exist or may not log in - * (e.g. because he is already logged in) - */ - private PlayerAuth getPlayerAuth(Player player) { - return getPlayerAuth(player, false); - } - - /** - * Checks the precondition for authentication (like user known) and returns - * the player's {@link PlayerAuth} object. - * - * @param player the player to check - * @param quiet don't send messages - * @return the PlayerAuth object, or {@code null} if the player doesn't exist or may not log in - * (e.g. because he is already logged in) - */ - private PlayerAuth getPlayerAuth(Player player, boolean quiet) { - String name = player.getName().toLowerCase(Locale.ROOT); - if (playerCache.isAuthenticated(name)) { - if (!quiet) { - service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - } - return null; - } - - PlayerAuth auth = dataSource.getAuth(name); - if (auth == null) { - if (!quiet) { - service.send(player, MessageKey.UNKNOWN_USER); - } - // Recreate the message task to immediately send the message again as response - limboService.resetMessageTask(player, LimboMessageType.REGISTER); - return null; - } - - if (!service.getProperty(DatabaseSettings.MYSQL_COL_GROUP).isEmpty() - && auth.getGroupId() == service.getProperty(HooksSettings.NON_ACTIVATED_USERS_GROUP)) { - if (!quiet) { - service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED); - } - return null; - } - - String ip = PlayerUtils.getPlayerIp(player); - if (hasReachedMaxLoggedInPlayersForIp(player, ip)) { - if (!quiet) { - service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - } - return null; - } - - boolean isAsync = service.getProperty(PluginSettings.USE_ASYNC_TASKS); - AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player, isAsync); - bukkitService.callEvent(event); - if (!event.canLogin()) { - return null; - } - return auth; - } - - /** - * Checks various conditions for regular player login (not used in force login). - * - * @param player the player requesting to log in - * @param auth the PlayerAuth object of the player - * @param password the password supplied by the player - * @return true if the password matches and all other conditions are met (e.g. no captcha required), - * false otherwise - */ - private boolean checkPlayerInfo(Player player, PlayerAuth auth, String password) { - String name = player.getName().toLowerCase(Locale.ROOT); - - // If captcha is required send a message to the player and deny to log in - if (loginCaptchaManager.isCaptchaRequired(name)) { - service.send(player, MessageKey.USAGE_CAPTCHA, loginCaptchaManager.getCaptchaCodeOrGenerateNew(name)); - return false; - } - - String ip = PlayerUtils.getPlayerIp(player); - - // Increase the counts here before knowing the result of the login. - loginCaptchaManager.increaseLoginFailureCount(name); - tempbanManager.increaseCount(ip, name); - - if (passwordSecurity.comparePassword(password, auth.getPassword(), player.getName())) { - return true; - } else { - handleWrongPassword(player, auth, ip); - return false; - } - } - - /** - * Handles a login with wrong password. - * - * @param player the player who attempted to log in - * @param auth the PlayerAuth object of the player - * @param ip the ip address of the player - */ - private void handleWrongPassword(Player player, PlayerAuth auth, String ip) { - logger.fine(player.getName() + " used the wrong password"); - - bukkitService.createAndCallEvent(isAsync -> new FailedLoginEvent(player, isAsync)); - if (tempbanManager.shouldTempban(ip)) { - tempbanManager.tempbanPlayer(player); - } else if (service.getProperty(RestrictionSettings.KICK_ON_WRONG_PASSWORD)) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask( - () -> player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.WRONG_PASSWORD))); - } else { - service.send(player, MessageKey.WRONG_PASSWORD); - - // If the authentication fails check if Captcha is required and send a message to the player - if (loginCaptchaManager.isCaptchaRequired(player.getName())) { - limboService.muteMessageTask(player); - service.send(player, MessageKey.USAGE_CAPTCHA, - loginCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName())); - } else if (emailService.hasAllInformation() && !Utils.isEmailEmpty(auth.getEmail())) { - service.send(player, MessageKey.FORGOT_PASSWORD_MESSAGE); - } - } - } - - /** - * Sets the player to the logged in state. - * - * @param player the player to log in - * @param auth the associated PlayerAuth object - */ - public void performLogin(Player player, PlayerAuth auth) { - if (player.isOnline()) { - boolean isFirstLogin = (auth.getLastLogin() == null); - - // Update auth to reflect this new login - String ip = PlayerUtils.getPlayerIp(player); - auth.setRealName(player.getName()); - auth.setLastLogin(System.currentTimeMillis()); - auth.setLastIp(ip); - dataSource.updateSession(auth); - - // TODO: send an update when a messaging service will be implemented (SESSION) - - // Successful login, so reset the captcha & temp ban count - String name = player.getName(); - loginCaptchaManager.resetLoginFailureCount(name); - tempbanManager.resetCount(ip, name); - player.setNoDamageTicks(0); - - service.send(player, MessageKey.LOGIN_SUCCESS); - - // Other auths - List auths = dataSource.getAllAuthsByIp(auth.getLastIp()); - displayOtherAccounts(auths, player); - - String email = auth.getEmail(); - if (service.getProperty(EmailSettings.RECALL_PLAYERS) && Utils.isEmailEmpty(email)) { - service.send(player, MessageKey.ADD_EMAIL_MESSAGE); - } - - logger.fine(player.getName() + " logged in " + ip); - - // makes player loggedin - playerCache.updatePlayer(auth); - dataSource.setLogged(name); - sessionService.grantSession(name); - - if (bungeeSender.isEnabled()) { - // As described at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ - // "Keep in mind that you can't send plugin messages directly after a player joins." - bukkitService.scheduleSyncDelayedTask(() -> - bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGIN), settings.getProperty(HooksSettings.PROXY_SEND_DELAY)); - } - - // As the scheduling executes the Task most likely after the current - // task, we schedule it in the end - // so that we can be sure, and have not to care if it might be - // processed in other order. - syncProcessManager.processSyncPlayerLogin(player, isFirstLogin, auths); - } else { - logger.warning("Player '" + player.getName() + "' wasn't online during login process, aborted..."); - } - } - - /** - * Sends info about the other accounts owned by the given player to the configured users. - * - * @param auths the names of the accounts also owned by the player - * @param player the player - */ - private void displayOtherAccounts(List auths, Player player) { - if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auths.size() <= 1) { - return; - } - - List formattedNames = new ArrayList<>(auths.size()); - for (String currentName : auths) { - Player currentPlayer = bukkitService.getPlayerExact(currentName); - if (currentPlayer != null && currentPlayer.isOnline()) { - formattedNames.add(ChatColor.GREEN + currentPlayer.getName() + ChatColor.GRAY); - } else { - formattedNames.add(currentName); - } - } - - String message = ChatColor.GRAY + String.join(", ", formattedNames) + "."; - - logger.fine("The user " + player.getName() + " has " + auths.size() + " accounts:"); - logger.fine(message); - - for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { - if (onlinePlayer.getName().equalsIgnoreCase(player.getName()) - && service.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) { - service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_SELF, Integer.toString(auths.size())); - onlinePlayer.sendMessage(message); - } else if (service.hasPermission(onlinePlayer, AdminPermission.SEE_OTHER_ACCOUNTS)) { - service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_OTHER, - player.getName(), Integer.toString(auths.size())); - onlinePlayer.sendMessage(message); - } - } - } - - /** - * Checks whether the maximum threshold of logged in player per IP address has been reached - * for the given player and IP address. - * - * @param player the player to process - * @param ip the associated ip address - * @return true if the threshold has been reached, false otherwise - */ - @VisibleForTesting - boolean hasReachedMaxLoggedInPlayersForIp(Player player, String ip) { - // Do not perform the check if player has multiple accounts permission or if IP is localhost - if (service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP) <= 0 - || service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) - || InternetProtocolUtils.isLoopbackAddress(ip)) { - return false; - } - - // Count logged in players with same IP address - String name = player.getName(); - int count = 0; - for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { - if (ip.equalsIgnoreCase(PlayerUtils.getPlayerIp(onlinePlayer)) - && !onlinePlayer.getName().equals(name) - && dataSource.isLogged(onlinePlayer.getName().toLowerCase(Locale.ROOT))) { - ++count; - } - } - return count >= service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP); - } -} diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java deleted file mode 100644 index ac022405..00000000 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ /dev/null @@ -1,132 +0,0 @@ -package fr.xephi.authme.process.login; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.events.LoginEvent; -import fr.xephi.authme.events.RestoreInventoryEvent; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.process.SynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.JoinMessageService; -import fr.xephi.authme.service.TeleportationService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffectType; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; - -public class ProcessSyncPlayerLogin implements SynchronousProcess { - - @Inject - private BungeeSender bungeeSender; - - @Inject - private VelocitySender velocitySender; - - @Inject - private LimboService limboService; - - @Inject - private BukkitService bukkitService; - - @Inject - private TeleportationService teleportationService; - - @Inject - private PlayerCache playerCache; - - @Inject - private CommandManager commandManager; - - @Inject - private CommonService commonService; - - @Inject - private JoinMessageService joinMessageService; - - @Inject - private PermissionsManager permissionsManager; - - ProcessSyncPlayerLogin() { - } - - private void restoreInventory(Player player) { - RestoreInventoryEvent event = new RestoreInventoryEvent(player); - bukkitService.callEvent(event); - if (!event.isCancelled()) { - player.updateInventory(); - } - } - - /** - * Performs operations in sync mode for a player that has just logged in. - * - * @param player the player that was logged in - * @param isFirstLogin true if this is the first time the player logged in - * @param authsWithSameIp registered names with the same IP address as the player's - */ - public void processPlayerLogin(Player player, boolean isFirstLogin, List authsWithSameIp) { - final String name = player.getName().toLowerCase(Locale.ROOT); - final LimboPlayer limbo = limboService.getLimboPlayer(name); - - // Limbo contains the State of the Player before /login - if (limbo != null) { - limboService.restoreData(player); - } - - if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { - restoreInventory(player); - } - - final PlayerAuth auth = playerCache.getAuth(name); - - // AuthMeReReloaded start - Fix #57 - if (isFirstLogin) { - auth.setQuitLocation(player.getLocation()); - } - // AuthMeReReloaded end - Fix #57 - - teleportationService.teleportOnLogin(player, auth, limbo); - - // We can now display the join message (if delayed) - joinMessageService.sendMessage(name); - - if (commonService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - player.removePotionEffect(PotionEffectType.BLINDNESS); - } - - // AuthMeVelocity start - send on player login - if (velocitySender.isEnabled()) { - bukkitService.scheduleSyncDelayedTask(() -> - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.LOGIN), commonService.getProperty(HooksSettings.PROXY_SEND_DELAY)); - } - // AuthMeVelocity end - - // The Login event now fires (as intended) after everything is processed - bukkitService.callEvent(new LoginEvent(player)); - - // Login is now finished; we can force all commands - if (isFirstLogin) { - commandManager.runCommandsOnFirstLogin(player, authsWithSameIp); - } - commandManager.runCommandsOnLogin(player, authsWithSameIp); - - if (!permissionsManager.hasPermission(player, PlayerStatePermission.BYPASS_BUNGEE_SEND)) { - // Send Bungee stuff. The service will check if it is enabled or not. - bungeeSender.connectPlayerOnLogin(player); - } - } -} diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java deleted file mode 100644 index 4b6af1e5..00000000 --- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java +++ /dev/null @@ -1,81 +0,0 @@ -package fr.xephi.authme.process.logout; - -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.SessionService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.bungeecord.MessageType; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -/** - * Async task when a player wants to log out. - */ -public class AsynchronousLogout implements AsynchronousProcess { - - @Inject - private DataSource database; - - @Inject - private CommonService service; - - @Inject - private PlayerCache playerCache; - - @Inject - private VerificationCodeManager codeManager; - - @Inject - private SyncProcessManager syncProcessManager; - - @Inject - private SessionService sessionService; - - @Inject - private BungeeSender bungeeSender; - @Inject - private VelocitySender velocitySender; - - AsynchronousLogout() { - } - - /** - * Handles a player's request to log out. - * - * @param player the player wanting to log out - */ - public void logout(Player player) { - String name = player.getName().toLowerCase(Locale.ROOT); - if (!playerCache.isAuthenticated(name)) { - service.send(player, MessageKey.NOT_LOGGED_IN); - return; - } - - PlayerAuth auth = playerCache.getAuth(name); - database.updateSession(auth); - // TODO: send an update when a messaging service will be implemented (SESSION) - //if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { - auth.setQuitLocation(player.getLocation()); - database.updateQuitLoc(auth); - // TODO: send an update when a messaging service will be implemented (QUITLOC) - //} AuthMeReReloaded - Always save quit location - - playerCache.removePlayer(name); - codeManager.unverify(name); - database.setUnlogged(name); - sessionService.revokeSession(name); - bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGOUT); - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.LOGOUT); - syncProcessManager.processSyncPlayerLogout(player); - } -} diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncPlayerLogout.java deleted file mode 100644 index 96865e21..00000000 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncPlayerLogout.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.xephi.authme.process.logout; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.events.LogoutEvent; -import fr.xephi.authme.listener.protocollib.ProtocolLibService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.SynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.TeleportationService; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND; - - -public class ProcessSyncPlayerLogout implements SynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncPlayerLogout.class); - - @Inject - private CommonService service; - - @Inject - private BukkitService bukkitService; - - @Inject - private ProtocolLibService protocolLibService; - - @Inject - private LimboService limboService; - - @Inject - private TeleportationService teleportationService; - - @Inject - private CommandManager commandManager; - - ProcessSyncPlayerLogout() { - } - - /** - * Processes a player which has been logged out. - * - * @param player the player logging out - */ - public void processSyncLogout(Player player) { - if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { - protocolLibService.sendBlankInventoryPacket(player); - } - - applyLogoutEffect(player); - commandManager.runCommandsOnLogout(player); - - // Player is now logout... Time to fire event ! - bukkitService.callEvent(new LogoutEvent(player)); - - service.send(player, MessageKey.LOGOUT_SUCCESS); - logger.info(player.getName() + " logged out"); - } - - private void applyLogoutEffect(Player player) { - // dismount player - player.leaveVehicle(); - teleportationService.teleportOnJoin(player); - - // Apply Blindness effect - if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; - player.addPotionEffect(bukkitService.createBlindnessEffect(timeout)); - } - - // Set player's data to unauthenticated - limboService.createLimboPlayer(player, true); - } - -} diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java deleted file mode 100644 index 31bb7078..00000000 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ /dev/null @@ -1,113 +0,0 @@ -package fr.xephi.authme.process.quit; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.data.VerificationCodeManager; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.SessionService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -/** - * Async process called when a player quits the server. - */ -public class AsynchronousQuit implements AsynchronousProcess { - - @Inject - private AuthMe plugin; - - @Inject - private DataSource database; - - @Inject - private CommonService service; - - @Inject - private PlayerCache playerCache; - - @Inject - private SyncProcessManager syncProcessManager; - - @Inject - private SpawnLoader spawnLoader; - - @Inject - private ValidationService validationService; - - @Inject - private VerificationCodeManager codeManager; - - @Inject - private SessionService sessionService; - - AsynchronousQuit() { - } - - /** - * Processes that the given player has quit the server. - * - * @param player the player who left - */ - public void processQuit(Player player) { - if (player == null || validationService.isUnrestricted(player.getName())) { - return; - } - String name = player.getName().toLowerCase(Locale.ROOT); - boolean wasLoggedIn = playerCache.isAuthenticated(name); - - if (wasLoggedIn) { - //if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { - // AuthMeReReloaded - Always save quit location on quit - Location loc = spawnLoader.getPlayerLocationOrSpawn(player); - PlayerAuth authLoc = PlayerAuth.builder() - .name(name).location(loc) - .realName(player.getName()).build(); - database.updateQuitLoc(authLoc); - // AuthMeReReloaded - Fix AuthMe#2769 -1 - //} - - - String ip = PlayerUtils.getPlayerIp(player); - PlayerAuth auth = PlayerAuth.builder() - .name(name) - .realName(player.getName()) - .lastIp(ip) - .lastLogin(System.currentTimeMillis()) - .build(); - database.updateSession(auth); - - // TODO: send an update when a messaging service will be implemented (QUITLOC) - } - - //always unauthenticate the player - use session only for auto logins on the same ip - playerCache.removePlayer(name); - codeManager.unverify(name); - - //always update the database when the player quit the game (if sessions are disabled) - if (wasLoggedIn) { - database.setUnlogged(name); - if (!service.getProperty(PluginSettings.SESSIONS_ENABLED)) { - sessionService.revokeSession(name); - } - } - - if (plugin.isEnabled()) { - syncProcessManager.processSyncPlayerQuit(player, wasLoggedIn); - } - - // remove player from cache - database.invalidateCache(name); - } - -} diff --git a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncPlayerQuit.java b/src/main/java/fr/xephi/authme/process/quit/ProcessSyncPlayerQuit.java deleted file mode 100644 index 42048ef1..00000000 --- a/src/main/java/fr/xephi/authme/process/quit/ProcessSyncPlayerQuit.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.xephi.authme.process.quit; - -import com.github.Anon8281.universalScheduler.UniversalScheduler; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.process.SynchronousProcess; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - - -public class ProcessSyncPlayerQuit implements SynchronousProcess { - - @Inject - private LimboService limboService; - - @Inject - private CommandManager commandManager; - - /** - * Processes a player having quit. - * - * @param player the player that left - * @param wasLoggedIn true if the player was logged in when leaving, false otherwise - */ - public void processSyncQuit(Player player, boolean wasLoggedIn) { - if (wasLoggedIn) { - commandManager.runCommandsOnLogout(player); - } else { - limboService.restoreData(player); - if (!UniversalScheduler.isFolia) { // AuthMeReReloaded - Fix #146 (Very stupid solution, but works) - player.saveData(); // #1238: Speed is sometimes not restored properly - } - } - player.leaveVehicle(); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java deleted file mode 100644 index a13bcf3c..00000000 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ /dev/null @@ -1,131 +0,0 @@ -package fr.xephi.authme.process.register; - -import ch.jalu.injector.factory.SingletonStore; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.AuthMeAsyncPreRegisterEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.process.register.executors.RegistrationExecutor; -import fr.xephi.authme.process.register.executors.RegistrationMethod; -import fr.xephi.authme.process.register.executors.RegistrationParameters; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.InternetProtocolUtils; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.List; -import java.util.Locale; - -import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS; - -/** - * Asynchronous processing of a request for registration. - */ -public class AsyncRegister implements AsynchronousProcess { - - @Inject - private DataSource database; - @Inject - private PlayerCache playerCache; - @Inject - private BukkitService bukkitService; - @Inject - private CommonService service; - @Inject - private SingletonStore registrationExecutorFactory; - - AsyncRegister() { - } - - /** - * Performs the registration process for the given player. - * - * @param variant the registration method - * @param parameters the parameters - * @param

parameters type - */ - public synchronized

void register(RegistrationMethod

variant, P parameters) { - if (preRegisterCheck(variant, parameters.getPlayer())) { - RegistrationExecutor

executor = registrationExecutorFactory.getSingleton(variant.getExecutorClass()); - if (executor.isRegistrationAdmitted(parameters)) { - executeRegistration(parameters, executor); - } - } - } - - /** - * Checks if the player is able to register, in that case the {@link AuthMeAsyncPreRegisterEvent} is invoked. - * - * @param variant the registration type variant. - * @param player the player which is trying to register. - * - * @return true if the checks are successful and the event hasn't marked the action as denied, false otherwise. - */ - private boolean preRegisterCheck(RegistrationMethod variant, Player player) { - String name = player.getName().toLowerCase(Locale.ROOT); - if (playerCache.isAuthenticated(name)) { - service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - return false; - } else if (!service.getProperty(RegistrationSettings.IS_ENABLED)) { - service.send(player, MessageKey.REGISTRATION_DISABLED); - return false; - } else if (database.isAuthAvailable(name)) { - service.send(player, MessageKey.NAME_ALREADY_REGISTERED); - return false; - } - - AuthMeAsyncPreRegisterEvent event = bukkitService.createAndCallEvent( - isAsync -> new AuthMeAsyncPreRegisterEvent(player, isAsync)); - if (!event.canRegister()) { - return false; - } - - return variant == RegistrationMethod.API_REGISTRATION || isPlayerIpAllowedToRegister(player); - } - - /** - * Executes the registration. - * - * @param parameters the registration parameters - * @param executor the executor to perform the registration process with - * @param

registration params type - */ - private

- void executeRegistration(P parameters, RegistrationExecutor

executor) { - PlayerAuth auth = executor.buildPlayerAuth(parameters); - if (database.saveAuth(auth)) { - executor.executePostPersistAction(parameters); - } else { - service.send(parameters.getPlayer(), MessageKey.ERROR); - } - } - - /** - * Checks whether the registration threshold has been exceeded for the given player's IP address. - * - * @param player the player to check - * - * @return true if registration may take place, false otherwise (IP check failed) - */ - private boolean isPlayerIpAllowedToRegister(Player player) { - int maxRegPerIp = service.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP); - String ip = PlayerUtils.getPlayerIp(player); - if (maxRegPerIp > 0 - && !InternetProtocolUtils.isLoopbackAddress(ip) - && !service.hasPermission(player, ALLOW_MULTIPLE_ACCOUNTS)) { - List otherAccounts = database.getAllAuthsByIp(ip); - if (otherAccounts.size() >= maxRegPerIp) { - service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerIp), - Integer.toString(otherAccounts.size()), String.join(", ", otherAccounts)); - return false; - } - } - return true; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java deleted file mode 100644 index 0fe19acf..00000000 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java +++ /dev/null @@ -1,52 +0,0 @@ -package fr.xephi.authme.process.register; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.events.RegisterEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.SynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Performs synchronous tasks after a successful {@link RegistrationType#EMAIL email registration}. - */ -public class ProcessSyncEmailRegister implements SynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncEmailRegister.class); - - @Inject - private BukkitService bukkitService; - - @Inject - private CommonService service; - - @Inject - private LimboService limboService; - @Inject - private VelocitySender velocitySender; - - ProcessSyncEmailRegister() { - } - - /** - * Performs sync tasks for a player which has just registered by email. - * - * @param player the recently registered player - */ - public void processEmailRegister(Player player) { - service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED); - limboService.replaceTasksAfterRegistration(player); - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.REGISTER); - bukkitService.callEvent(new RegisterEvent(player)); - logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player)); - } - -} diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java deleted file mode 100644 index f68ba015..00000000 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ /dev/null @@ -1,96 +0,0 @@ -package fr.xephi.authme.process.register; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.events.RegisterEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.SynchronousProcess; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Performs synchronous tasks after a successful {@link RegistrationType#PASSWORD password registration}. - */ -public class ProcessSyncPasswordRegister implements SynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncPasswordRegister.class); - - @Inject - private BungeeSender bungeeSender; - - @Inject - private VelocitySender velocitySender; - - @Inject - private CommonService service; - - @Inject - private LimboService limboService; - - @Inject - private CommandManager commandManager; - - @Inject - private BukkitService bukkitService; - - ProcessSyncPasswordRegister() { - } - - /** - * Request that the player log in. - * - * @param player the player - */ - private void requestLogin(Player player) { - limboService.replaceTasksAfterRegistration(player); - - if (player.isInsideVehicle() && player.getVehicle() != null) { - player.getVehicle().eject(); - } - } - - /** - * Processes a player having registered with a password. - * - * @param player the newly registered player - */ - public void processPasswordRegister(Player player) { - service.send(player, MessageKey.REGISTER_SUCCESS); - - if (!service.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) { - service.send(player, MessageKey.ADD_EMAIL_MESSAGE); - } - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.REGISTER); - bukkitService.callEvent(new RegisterEvent(player)); - logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player)); - - // Kick Player after Registration is enabled, kick the player - if (service.getProperty(RegistrationSettings.FORCE_KICK_AFTER_REGISTER)) { - player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.REGISTER_SUCCESS)); - return; - } - - // Register is now finished; we can force all commands - commandManager.runCommandsOnRegister(player); - - // Request login after registration - if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) { - requestLogin(player); - return; - } - - // Send Bungee stuff. The service will check if it is enabled or not. - bungeeSender.connectPlayerOnLogin(player); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/RegisterSecondaryArgument.java b/src/main/java/fr/xephi/authme/process/register/RegisterSecondaryArgument.java deleted file mode 100644 index 4ac4f2d5..00000000 --- a/src/main/java/fr/xephi/authme/process/register/RegisterSecondaryArgument.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme.process.register; - -/** - * Type of the second argument of the {@code /register} command. - */ -public enum RegisterSecondaryArgument { - - /** No second argument. */ - NONE, - - /** Confirmation of the first argument. */ - CONFIRMATION, - - /** For password registration, mandatory secondary argument is email. */ - EMAIL_MANDATORY, - - /** For password registration, optional secondary argument is email. */ - EMAIL_OPTIONAL - -} diff --git a/src/main/java/fr/xephi/authme/process/register/RegistrationType.java b/src/main/java/fr/xephi/authme/process/register/RegistrationType.java deleted file mode 100644 index 7b03b1c2..00000000 --- a/src/main/java/fr/xephi/authme/process/register/RegistrationType.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.xephi.authme.process.register; - -/** - * Registration type. - */ -public enum RegistrationType { - - /** - * Password registration: account is registered with a password supplied by the player. - */ - PASSWORD, - - /** - * Email registration: account is registered with an email supplied by the player. A password - * is generated and sent to the email address. - */ - EMAIL - -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterExecutor.java deleted file mode 100644 index 179aa59d..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterExecutor.java +++ /dev/null @@ -1,99 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.process.login.AsynchronousLogin; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.ValidationService; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Registration executor for registration methods where the password - * is supplied by the user. - * - * @param

the parameters type - */ -abstract class AbstractPasswordRegisterExecutor

- implements RegistrationExecutor

{ - - /** - * Number of ticks to wait before running the login action when it is run synchronously. - * A small delay is necessary or the database won't return the newly saved PlayerAuth object - * and the login process thinks the user is not registered. - */ - private static final int SYNC_LOGIN_DELAY = 5; - - @Inject - private ValidationService validationService; - - @Inject - private CommonService commonService; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private BukkitService bukkitService; - - @Inject - private SyncProcessManager syncProcessManager; - - @Inject - private AsynchronousLogin asynchronousLogin; - - @Override - public boolean isRegistrationAdmitted(P params) { - ValidationService.ValidationResult passwordValidation = validationService.validatePassword( - params.getPassword(), params.getPlayer().getName()); - if (passwordValidation.hasError()) { - commonService.send(params.getPlayer(), passwordValidation.getMessageKey(), passwordValidation.getArgs()); - return false; - } - return true; - } - - @Override - public PlayerAuth buildPlayerAuth(P params) { - HashedPassword hashedPassword = passwordSecurity.computeHash(params.getPassword(), params.getPlayerName()); - params.setHashedPassword(hashedPassword); - return createPlayerAuthObject(params); - } - - /** - * Creates the PlayerAuth object to store into the database, based on the registration parameters. - * - * @param params the parameters - * @return the PlayerAuth representing the new account to register - */ - protected abstract PlayerAuth createPlayerAuthObject(P params); - - /** - * Returns whether the player should be automatically logged in after registration. - * - * @param params the registration parameters - * @return true if the player should be logged in, false otherwise - */ - protected boolean performLoginAfterRegister(P params) { - return !commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER); - } - - @Override - public void executePostPersistAction(P params) { - final Player player = params.getPlayer(); - if (performLoginAfterRegister(params)) { - if (commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)) { - bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player)); - } else { - bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY); - } - } - syncProcessManager.processSyncPasswordRegister(player); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterParams.java b/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterParams.java deleted file mode 100644 index 0c7a1d51..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/AbstractPasswordRegisterParams.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.security.crypts.HashedPassword; -import org.bukkit.entity.Player; - -/** - * Common params type for implementors of {@link AbstractPasswordRegisterExecutor}. - * Password must be supplied on creation and cannot be changed later on. The {@link HashedPassword} - * is stored on the params object for later use. - */ -public abstract class AbstractPasswordRegisterParams extends RegistrationParameters { - - private final String password; - private HashedPassword hashedPassword; - - /** - * Constructor. - * - * @param player the player to register - * @param password the password to use - */ - public AbstractPasswordRegisterParams(Player player, String password) { - super(player); - this.password = password; - } - - /** - * Constructor with no defined password. Use for registration methods which - * have no implicit password (like two factor authentication). - * - * @param player the player to register - */ - public AbstractPasswordRegisterParams(Player player) { - this(player, null); - } - - public String getPassword() { - return password; - } - - void setHashedPassword(HashedPassword hashedPassword) { - this.hashedPassword = hashedPassword; - } - - HashedPassword getHashedPassword() { - return hashedPassword; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterExecutor.java deleted file mode 100644 index 6005c8e4..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterExecutor.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; - -/** - * Executor for password registration via API call. - */ -class ApiPasswordRegisterExecutor extends AbstractPasswordRegisterExecutor { - - @Override - protected PlayerAuth createPlayerAuthObject(ApiPasswordRegisterParams params) { - return PlayerAuthBuilderHelper - .createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null); - } - - @Override - protected boolean performLoginAfterRegister(ApiPasswordRegisterParams params) { - return params.getLoginAfterRegister(); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterParams.java b/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterParams.java deleted file mode 100644 index 357d32c2..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/ApiPasswordRegisterParams.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import org.bukkit.entity.Player; - -/** - * Parameters for {@link ApiPasswordRegisterExecutor}. - */ -public class ApiPasswordRegisterParams extends PasswordRegisterParams { - - private final boolean loginAfterRegister; - - protected ApiPasswordRegisterParams(Player player, String password, boolean loginAfterRegister) { - super(player, password, null); - this.loginAfterRegister = loginAfterRegister; - } - - /** - * Creates a parameters object. - * - * @param player the player to register - * @param password the password to register with - * @param loginAfterRegister whether the player should be logged in after registration - * @return params object with the given data - */ - public static ApiPasswordRegisterParams of(Player player, String password, boolean loginAfterRegister) { - return new ApiPasswordRegisterParams(player, password, loginAfterRegister); - } - - /** - * @return true if the player should be logged in after being registered, false otherwise - */ - public boolean getLoginAfterRegister() { - return loginAfterRegister; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterExecutor.java deleted file mode 100644 index 2224c23c..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterExecutor.java +++ /dev/null @@ -1,81 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.process.SyncProcessManager; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.RandomStringUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.text.SimpleDateFormat; -import java.util.Date; - -import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS; -import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth; -import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH; - -/** - * Executor for email registration: the player only provides his email address, - * to which a generated password is sent. - */ -class EmailRegisterExecutor implements RegistrationExecutor { - - @Inject - private DataSource dataSource; - - @Inject - private CommonService commonService; - - @Inject - private EmailService emailService; - - @Inject - private SyncProcessManager syncProcessManager; - - @Inject - private PasswordSecurity passwordSecurity; - - @Override - public boolean isRegistrationAdmitted(EmailRegisterParams params) { - final int maxRegPerEmail = commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL); - if (maxRegPerEmail > 0 && !commonService.hasPermission(params.getPlayer(), ALLOW_MULTIPLE_ACCOUNTS)) { - int otherAccounts = dataSource.countAuthsByEmail(params.getEmail()); - if (otherAccounts >= maxRegPerEmail) { - commonService.send(params.getPlayer(), MessageKey.MAX_REGISTER_EXCEEDED, - Integer.toString(maxRegPerEmail), Integer.toString(otherAccounts), "@"); - return false; - } - } - return true; - } - - @Override - public PlayerAuth buildPlayerAuth(EmailRegisterParams params) { - String password = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH)); - HashedPassword hashedPassword = passwordSecurity.computeHash(password, params.getPlayer().getName()); - params.setPassword(password); - return createPlayerAuth(params.getPlayer(), hashedPassword, params.getEmail()); - } - - @Override - public void executePostPersistAction(EmailRegisterParams params) { - Player player = params.getPlayer(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'年'MM'月'dd'日' HH:mm:ss"); - Date date = new Date(System.currentTimeMillis()); - boolean couldSendMail = emailService.sendNewPasswordMail( - player.getName(), params.getEmail(), params.getPassword(), PlayerUtils.getPlayerIp(player), dateFormat.format(date)); - if (couldSendMail) { - syncProcessManager.processSyncEmailRegister(player); - } else { - commonService.send(player, MessageKey.EMAIL_SEND_FAILURE); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterParams.java b/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterParams.java deleted file mode 100644 index 94d03acc..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/EmailRegisterParams.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import org.bukkit.entity.Player; - -/** - * Parameters for email registration. - */ -public class EmailRegisterParams extends RegistrationParameters { - - private final String email; - private String password; - - protected EmailRegisterParams(Player player, String email) { - super(player); - this.email = email; - } - - /** - * Creates a params object for email registration. - * - * @param player the player to register - * @param email the player's email - * @return params object with the given data - */ - public static EmailRegisterParams of(Player player, String email) { - return new EmailRegisterParams(player, email); - } - - public String getEmail() { - return email; - } - - void setPassword(String password) { - this.password = password; - } - - /** - * @return the password generated for the player - */ - String getPassword() { - return password; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterExecutor.java deleted file mode 100644 index 5b1558bc..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterExecutor.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; - -import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth; - -/** - * Registration executor for password registration. - */ -class PasswordRegisterExecutor extends AbstractPasswordRegisterExecutor { - - @Override - public synchronized PlayerAuth createPlayerAuthObject(PasswordRegisterParams params) { - return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), params.getEmail()); - } - -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterParams.java b/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterParams.java deleted file mode 100644 index f21861bf..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/PasswordRegisterParams.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import org.bukkit.entity.Player; - -/** - * Parameters for registration with a given password, and optionally an email address. - */ -public class PasswordRegisterParams extends AbstractPasswordRegisterParams { - - private final String email; - - protected PasswordRegisterParams(Player player, String password, String email) { - super(player, password); - this.email = email; - } - - /** - * Creates a params object. - * - * @param player the player to register - * @param password the password to register with - * @param email the email of the player (may be null) - * @return params object with the given data - */ - public static PasswordRegisterParams of(Player player, String password, String email) { - return new PasswordRegisterParams(player, password, email); - } - - public String getEmail() { - return email; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/PlayerAuthBuilderHelper.java b/src/main/java/fr/xephi/authme/process/register/executors/PlayerAuthBuilderHelper.java deleted file mode 100644 index 9b29dac2..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/PlayerAuthBuilderHelper.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Player; - -import java.util.Locale; - -/** - * Helper for constructing PlayerAuth objects. - */ -final class PlayerAuthBuilderHelper { - - private PlayerAuthBuilderHelper() { - } - - /** - * Creates a {@link PlayerAuth} object with the given data. - * - * @param player the player to create a PlayerAuth for - * @param hashedPassword the hashed password - * @param email the email address (nullable) - * @return the generated PlayerAuth object - */ - static PlayerAuth createPlayerAuth(Player player, HashedPassword hashedPassword, String email) { - return PlayerAuth.builder() - .name(player.getName().toLowerCase(Locale.ROOT)) - .realName(player.getName()) - .password(hashedPassword) - .email(email) - .registrationIp(PlayerUtils.getPlayerIp(player)) - .registrationDate(System.currentTimeMillis()) - .uuid(player.getUniqueId()) - .build(); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/RegistrationExecutor.java deleted file mode 100644 index 32bfd951..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; - -/** - * Performs the registration action. - * - * @param

the registration parameters type - */ -public interface RegistrationExecutor

{ - - /** - * Returns whether the registration may take place. Use this method to execute - * checks specific to the registration method. - *

- * If this method returns {@code false}, it is expected that the executor inform - * the player about the error within this method call. - * - * @param params the parameters for the registration - * @return true if registration may be performed, false otherwise - */ - boolean isRegistrationAdmitted(P params); - - /** - * Constructs the PlayerAuth object to persist into the database. - * - * @param params the parameters for the registration - * @return the player auth to register in the data source - */ - PlayerAuth buildPlayerAuth(P params); - - /** - * Follow-up method called after the player auth could be added into the database. - * - * @param params the parameters for the registration - */ - void executePostPersistAction(P params); - -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationMethod.java b/src/main/java/fr/xephi/authme/process/register/executors/RegistrationMethod.java deleted file mode 100644 index f5f38b86..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationMethod.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -/** - * Methods with which a player can be registered. - *

- * These constants each define a different way of registering a player and define the - * {@link RegistrationParameters parameters} and {@link RegistrationExecutor executor} - * classes which perform this registration method. This is essentially a typed enum - * as passing a constant of this class along with a parameters object to a method can - * be restricted to the correct parameters type. - * - * @param

the registration parameters type the method uses - */ -public final class RegistrationMethod

{ - - /** - * Password registration. - */ - public static final RegistrationMethod PASSWORD_REGISTRATION = - new RegistrationMethod<>(PasswordRegisterExecutor.class); - - /** - * Registration with two-factor authentication as login means. - */ - public static final RegistrationMethod TWO_FACTOR_REGISTRATION = - new RegistrationMethod<>(TwoFactorRegisterExecutor.class); - - /** - * Email registration: an email address is provided, to which a generated password is sent. - */ - public static final RegistrationMethod EMAIL_REGISTRATION = - new RegistrationMethod<>(EmailRegisterExecutor.class); - - /** - * API registration: player and password are provided via an API method. - */ - public static final RegistrationMethod API_REGISTRATION = - new RegistrationMethod<>(ApiPasswordRegisterExecutor.class); - - - private final Class> executorClass; - - private RegistrationMethod(Class> executorClass) { - this.executorClass = executorClass; - } - - /** - * @return the executor class to perform the registration method - */ - public Class> getExecutorClass() { - return executorClass; - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationParameters.java b/src/main/java/fr/xephi/authme/process/register/executors/RegistrationParameters.java deleted file mode 100644 index c92d57ff..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/RegistrationParameters.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import org.bukkit.entity.Player; - -/** - * Parent of all registration parameters. - */ -public abstract class RegistrationParameters { - - private final Player player; - - /** - * Constructor. - * - * @param player the player to perform the registration for - */ - public RegistrationParameters(Player player) { - this.player = player; - } - - public Player getPlayer() { - return player; - } - - public String getPlayerName() { - return player.getName(); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java b/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java deleted file mode 100644 index c84a70ab..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterExecutor.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.security.crypts.TwoFactor; -import fr.xephi.authme.service.CommonService; -import org.bukkit.Bukkit; - -import javax.inject.Inject; - -import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth; - -/** - * Executor for two-factor registration. - */ -class TwoFactorRegisterExecutor extends AbstractPasswordRegisterExecutor { - - @Inject - private CommonService commonService; - - @Override - public boolean isRegistrationAdmitted(TwoFactorRegisterParams params) { - // nothing to check - return true; - } - - @Override - protected PlayerAuth createPlayerAuthObject(TwoFactorRegisterParams params) { - return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null); - } - - @Override - public void executePostPersistAction(TwoFactorRegisterParams params) { - super.executePostPersistAction(params); - - // Note ljacqu 20170317: This two-factor registration type is only invoked when the password hash is configured - // to two-factor authentication. Therefore, the hashed password is the result of the TwoFactor EncryptionMethod - // implementation (contains the TOTP secret). - String hash = params.getHashedPassword().getHash(); - String qrCodeUrl = TwoFactor.getQrBarcodeUrl(params.getPlayerName(), Bukkit.getIp(), hash); - commonService.send(params.getPlayer(), MessageKey.TWO_FACTOR_CREATE, hash, qrCodeUrl); - } -} diff --git a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterParams.java b/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterParams.java deleted file mode 100644 index a7a75875..00000000 --- a/src/main/java/fr/xephi/authme/process/register/executors/TwoFactorRegisterParams.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.process.register.executors; - -import org.bukkit.entity.Player; - -/** - * Parameters for registration with two-factor authentication. - */ -public class TwoFactorRegisterParams extends AbstractPasswordRegisterParams { - - protected TwoFactorRegisterParams(Player player) { - super(player); - } - - /** - * Creates a parameters object. - * - * @param player the player to register - * @return params object with the given player - */ - public static TwoFactorRegisterParams of(Player player) { - return new TwoFactorRegisterParams(player); - } -} diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java deleted file mode 100644 index caecd295..00000000 --- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java +++ /dev/null @@ -1,155 +0,0 @@ -package fr.xephi.authme.process.unregister; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboService; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.UnregisterByAdminEvent; -import fr.xephi.authme.events.UnregisterByPlayerEvent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.AsynchronousProcess; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.CommonService; -import fr.xephi.authme.service.TeleportationService; -import fr.xephi.authme.service.bungeecord.BungeeSender; -import fr.xephi.authme.service.bungeecord.MessageType; -import fr.xephi.authme.service.velocity.VMessageType; -import fr.xephi.authme.service.velocity.VelocitySender; -import fr.xephi.authme.settings.commandconfig.CommandManager; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND; - -public class AsynchronousUnregister implements AsynchronousProcess { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousUnregister.class); - - @Inject - private DataSource dataSource; - - @Inject - private CommonService service; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private PlayerCache playerCache; - - @Inject - private BukkitService bukkitService; - - @Inject - private LimboService limboService; - - @Inject - private TeleportationService teleportationService; - - @Inject - private CommandManager commandManager; - - @Inject - private VelocitySender velocitySender; - - @Inject - private BungeeSender bungeeSender; - - AsynchronousUnregister() { - } - - /** - * Processes a player's request to unregister himself. Unregisters the player after - * successful password check. - * - * @param player the player - * @param password the input password to check before unregister - */ - public void unregister(Player player, String password) { - String name = player.getName(); - PlayerAuth cachedAuth = playerCache.getAuth(name); - if (passwordSecurity.comparePassword(password, cachedAuth.getPassword(), name)) { - if (dataSource.removeAuth(name)) { - performPostUnregisterActions(name, player); - logger.info(name + " unregistered himself"); - velocitySender.sendAuthMeVelocityMessage(player, VMessageType.UNREGISTER); - bukkitService.createAndCallEvent(isAsync -> new UnregisterByPlayerEvent(player, isAsync)); - } else { - service.send(player, MessageKey.ERROR); - } - } else { - service.send(player, MessageKey.WRONG_PASSWORD); - } - } - - /** - * Unregisters a player as administrator or console. - * - * @param initiator the initiator of this process (nullable) - * @param name the name of the player - * @param player the according Player object (nullable) - */ - // We need to have the name and the player separate because Player might be null in this case: - // we might have some player in the database that has never been online on the server - public void adminUnregister(CommandSender initiator, String name, Player player) { - if (dataSource.removeAuth(name)) { - performPostUnregisterActions(name, player); - if (player != null) velocitySender.sendAuthMeVelocityMessage(player, VMessageType.FORCE_UNREGISTER); - bukkitService.createAndCallEvent(isAsync -> new UnregisterByAdminEvent(player, name, isAsync, initiator)); - if (initiator == null) { - logger.info(name + " was unregistered"); - } else { - logger.info(name + " was unregistered by " + initiator.getName()); - service.send(initiator, MessageKey.UNREGISTERED_SUCCESS); - } - } else if (initiator != null) { - service.send(initiator, MessageKey.ERROR); - } - } - - /** - * Process the post unregister actions. Makes the user status consistent. - * - * @param name the name of the player - * @param player the according Player object (nullable) - */ - private void performPostUnregisterActions(String name, Player player) { - if (player != null && playerCache.isAuthenticated(name)) { - bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGOUT); - } - playerCache.removePlayer(name); - - // TODO: send an update when a messaging service will be implemented (UNREGISTER) - - if (player == null || !player.isOnline()) { - return; - } - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> - commandManager.runCommandsOnUnregister(player)); - - if (service.getProperty(RegistrationSettings.FORCE)) { - teleportationService.teleportOnJoin(player); - - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> { - limboService.createLimboPlayer(player, false); - applyBlindEffect(player); - }); - } - service.send(player, MessageKey.UNREGISTERED_SUCCESS); - } - - private void applyBlindEffect(Player player) { - if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { - int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; - bukkitService.runTaskIfFolia(player, () -> player.addPotionEffect(bukkitService.createBlindnessEffect(timeout))); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java deleted file mode 100644 index d1085fde..00000000 --- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java +++ /dev/null @@ -1,60 +0,0 @@ -package fr.xephi.authme.security; - -import fr.xephi.authme.security.crypts.EncryptionMethod; - -/** - * Hash algorithms supported by AuthMe. - */ -public enum HashAlgorithm { - - ARGON2(fr.xephi.authme.security.crypts.Argon2.class), - BCRYPT(fr.xephi.authme.security.crypts.BCrypt.class), - BCRYPT2Y(fr.xephi.authme.security.crypts.BCrypt2y.class), - CMW(fr.xephi.authme.security.crypts.CmwCrypt.class), - CRAZYCRYPT1(fr.xephi.authme.security.crypts.CrazyCrypt1.class), - IPB3(fr.xephi.authme.security.crypts.Ipb3.class), - IPB4(fr.xephi.authme.security.crypts.Ipb4.class), - JOOMLA(fr.xephi.authme.security.crypts.Joomla.class), - MD5VB(fr.xephi.authme.security.crypts.Md5vB.class), - MYBB(fr.xephi.authme.security.crypts.MyBB.class), - PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class), - PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class), - PHPBB(fr.xephi.authme.security.crypts.PhpBB.class), - PHPFUSION(fr.xephi.authme.security.crypts.PhpFusion.class), - ROYALAUTH(fr.xephi.authme.security.crypts.RoyalAuth.class), - SALTED2MD5(fr.xephi.authme.security.crypts.Salted2Md5.class), - SALTEDSHA512(fr.xephi.authme.security.crypts.SaltedSha512.class), - SHA256(fr.xephi.authme.security.crypts.Sha256.class), - SMF(fr.xephi.authme.security.crypts.Smf.class), - TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class), - WBB3(fr.xephi.authme.security.crypts.Wbb3.class), - WBB4(fr.xephi.authme.security.crypts.Wbb4.class), - WORDPRESS(fr.xephi.authme.security.crypts.Wordpress.class), - XAUTH(fr.xephi.authme.security.crypts.XAuth.class), - XFBCRYPT(fr.xephi.authme.security.crypts.XfBCrypt.class), - NOCRYPT(fr.xephi.authme.security.crypts.NoCrypt.class), - CUSTOM(null), - - @Deprecated DOUBLEMD5(fr.xephi.authme.security.crypts.DoubleMd5.class), - @Deprecated MD5(fr.xephi.authme.security.crypts.Md5.class), - @Deprecated PLAINTEXT(null), - @Deprecated SHA1(fr.xephi.authme.security.crypts.Sha1.class), - @Deprecated SHA512(fr.xephi.authme.security.crypts.Sha512.class), - @Deprecated WHIRLPOOL(fr.xephi.authme.security.crypts.Whirlpool.class); - - private final Class clazz; - - /** - * Constructor for HashAlgorithm. - * - * @param clazz The class of the hash implementation. - */ - HashAlgorithm(Class clazz) { - this.clazz = clazz; - } - - public Class getClazz() { - return clazz; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/HashUtils.java b/src/main/java/fr/xephi/authme/security/HashUtils.java deleted file mode 100644 index e8088078..00000000 --- a/src/main/java/fr/xephi/authme/security/HashUtils.java +++ /dev/null @@ -1,121 +0,0 @@ -package fr.xephi.authme.security; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * Hashing utilities (interface for common hashing algorithms). - */ -public final class HashUtils { - - private HashUtils() { - } - - /** - * Generate the SHA-1 digest of the given message. - * - * @param message The message to hash - * @return The resulting SHA-1 digest - */ - public static String sha1(String message) { - return hash(message, MessageDigestAlgorithm.SHA1); - } - - /** - * Generate the SHA-256 digest of the given message. - * - * @param message The message to hash - * @return The resulting SHA-256 digest - */ - public static String sha256(String message) { - return hash(message, MessageDigestAlgorithm.SHA256); - } - - /** - * Generate the SHA-512 digest of the given message. - * - * @param message The message to hash - * @return The resulting SHA-512 digest - */ - public static String sha512(String message) { - return hash(message, MessageDigestAlgorithm.SHA512); - } - - /** - * Generate the MD5 digest of the given message. - * - * @param message The message to hash - * @return The resulting MD5 digest - */ - public static String md5(String message) { - return hash(message, MessageDigestAlgorithm.MD5); - } - - /** - * Return a {@link MessageDigest} instance for the given algorithm. - * - * @param algorithm The desired algorithm - * @return MessageDigest instance for the given algorithm - */ - public static MessageDigest getDigest(MessageDigestAlgorithm algorithm) { - try { - return MessageDigest.getInstance(algorithm.getKey()); - } catch (NoSuchAlgorithmException e) { - throw new UnsupportedOperationException("Your system seems not to support the hash algorithm '" - + algorithm.getKey() + "'"); - } - } - - /** - * Return whether the given hash starts like a BCrypt hash. Checking with this method - * beforehand prevents the BCryptHasher from throwing certain exceptions. - * - * @param hash The salt to verify - * @return True if the salt is valid, false otherwise - */ - public static boolean isValidBcryptHash(String hash) { - return hash.length() == 60 && hash.substring(0, 2).equals("$2"); - } - - /** - * Checks whether the two strings are equal to each other in a time-constant manner. - * This helps to avoid timing side channel attacks, - * cf. issue #1561. - * - * @param string1 first string - * @param string2 second string - * @return true if the strings are equal to each other, false otherwise - */ - public static boolean isEqual(String string1, String string2) { - return MessageDigest.isEqual( - string1.getBytes(StandardCharsets.UTF_8), string2.getBytes(StandardCharsets.UTF_8)); - } - - /** - * Hash the message with the given algorithm and return the hash in its hexadecimal notation. - * - * @param message The message to hash - * @param algorithm The algorithm to hash the message with - * @return The digest in its hexadecimal representation - */ - public static String hash(String message, MessageDigest algorithm) { - algorithm.reset(); - algorithm.update(message.getBytes()); - byte[] digest = algorithm.digest(); - return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest)); - } - - /** - * Hash the message with the given algorithm and return the hash in its hexadecimal notation. - * - * @param message The message to hash - * @param algorithm The algorithm to hash the message with - * @return The digest in its hexadecimal representation - */ - private static String hash(String message, MessageDigestAlgorithm algorithm) { - return hash(message, getDigest(algorithm)); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/MessageDigestAlgorithm.java b/src/main/java/fr/xephi/authme/security/MessageDigestAlgorithm.java deleted file mode 100644 index 51ff2a5d..00000000 --- a/src/main/java/fr/xephi/authme/security/MessageDigestAlgorithm.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.security; - -import java.security.MessageDigest; - -/** - * The Java-supported names to get a {@link MessageDigest} instance with. - * - * @see - * Crypto Spec Appendix A: Standard Names - */ -public enum MessageDigestAlgorithm { - - MD5("MD5"), - - SHA1("SHA-1"), - - SHA256("SHA-256"), - - SHA512("SHA-512"); - - private final String key; - - MessageDigestAlgorithm(String key) { - this.key = key; - } - - public String getKey() { - return key; - } -} diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java deleted file mode 100644 index 012fd3e5..00000000 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ /dev/null @@ -1,164 +0,0 @@ -package fr.xephi.authme.security; - -import ch.jalu.injector.factory.Factory; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.PasswordEncryptionEvent; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.security.crypts.EncryptionMethod; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import org.bukkit.plugin.PluginManager; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.util.Collection; -import java.util.Locale; - -/** - * Manager class for password-related operations. - */ -public class PasswordSecurity implements Reloadable { - - @Inject - private Settings settings; - - @Inject - private DataSource dataSource; - - @Inject - private PluginManager pluginManager; - - @Inject - private Factory encryptionMethodFactory; - - private EncryptionMethod encryptionMethod; - private Collection legacyAlgorithms; - - /** - * Load or reload the configuration. - */ - @PostConstruct - @Override - public void reload() { - HashAlgorithm algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); - this.encryptionMethod = initializeEncryptionMethodWithEvent(algorithm); - this.legacyAlgorithms = settings.getProperty(SecuritySettings.LEGACY_HASHES); - } - - /** - * Compute the hash of the configured algorithm for the given password and username. - * - * @param password The password to hash - * @param playerName The player's name - * - * @return The password hash - */ - public HashedPassword computeHash(String password, String playerName) { - String playerLowerCase = playerName.toLowerCase(Locale.ROOT); - return encryptionMethod.computeHash(password, playerLowerCase); - } - - /** - * Check if the given password matches the player's stored password. - * - * @param password The password to check - * @param playerName The player to check for - * - * @return True if the password is correct, false otherwise - */ - public boolean comparePassword(String password, String playerName) { - HashedPassword auth = dataSource.getPassword(playerName); - return auth != null && comparePassword(password, auth, playerName); - } - - /** - * Check if the given password matches the given hashed password. - * - * @param password The password to check - * @param hashedPassword The hashed password to check against - * @param playerName The player to check for - * - * @return True if the password matches, false otherwise - */ - public boolean comparePassword(String password, HashedPassword hashedPassword, String playerName) { - String playerLowerCase = playerName.toLowerCase(Locale.ROOT); - return methodMatches(encryptionMethod, password, hashedPassword, playerLowerCase) - || compareWithLegacyHashes(password, hashedPassword, playerLowerCase); - } - - /** - * Compare the given hash with the configured legacy encryption methods to support - * the migration to a new encryption method. Upon a successful match, the password - * will be hashed with the new encryption method and persisted. - * - * @param password The clear-text password to check - * @param hashedPassword The encrypted password to test the clear-text password against - * @param playerName The name of the player - * - * @return True if there was a password match with a configured legacy encryption method, false otherwise - */ - private boolean compareWithLegacyHashes(String password, HashedPassword hashedPassword, String playerName) { - for (HashAlgorithm algorithm : legacyAlgorithms) { - EncryptionMethod method = initializeEncryptionMethod(algorithm); - if (methodMatches(method, password, hashedPassword, playerName)) { - hashAndSavePasswordWithNewAlgorithm(password, playerName); - return true; - } - } - return false; - } - - /** - * Verify with the given encryption method whether the password matches the hash after checking that - * the method can be called safely with the given data. - * - * @param method The encryption method to use - * @param password The password to check - * @param hashedPassword The hash to check against - * @param playerName The name of the player - * - * @return True if the password matched, false otherwise - */ - private static boolean methodMatches(EncryptionMethod method, String password, - HashedPassword hashedPassword, String playerName) { - return method != null && (!method.hasSeparateSalt() || hashedPassword.getSalt() != null) - && method.comparePassword(password, hashedPassword, playerName); - } - - /** - * Get the encryption method from the given {@link HashAlgorithm} value and emit a - * {@link PasswordEncryptionEvent}. The encryption method from the event is then returned, - * which may have been changed by an external listener. - * - * @param algorithm The algorithm to retrieve the encryption method for - * - * @return The encryption method - */ - private EncryptionMethod initializeEncryptionMethodWithEvent(HashAlgorithm algorithm) { - EncryptionMethod method = initializeEncryptionMethod(algorithm); - PasswordEncryptionEvent event = new PasswordEncryptionEvent(method); - pluginManager.callEvent(event); - return event.getMethod(); - } - - /** - * Initialize the encryption method associated with the given hash algorithm. - * - * @param algorithm The algorithm to retrieve the encryption method for - * - * @return The associated encryption method, or null if CUSTOM / deprecated - */ - private EncryptionMethod initializeEncryptionMethod(HashAlgorithm algorithm) { - if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) { - return null; - } - return encryptionMethodFactory.newInstance(algorithm.getClazz()); - } - - private void hashAndSavePasswordWithNewAlgorithm(String password, String playerName) { - HashedPassword hashedPassword = encryptionMethod.computeHash(password, playerName); - dataSource.updatePassword(playerName, hashedPassword); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Argon2.java b/src/main/java/fr/xephi/authme/security/crypts/Argon2.java deleted file mode 100644 index e002886b..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Argon2.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import de.mkammerer.argon2.Argon2Constants; -import de.mkammerer.argon2.Argon2Factory; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -@Recommendation(Usage.RECOMMENDED) -@HasSalt(value = SaltType.TEXT, length = Argon2Constants.DEFAULT_SALT_LENGTH) -// Note: Argon2 is actually a salted algorithm but salt generation is handled internally -// and isn't exposed to the outside, so we treat it as an unsalted implementation -public class Argon2 extends UnsaltedMethod { - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(Argon2.class); - - private de.mkammerer.argon2.Argon2 argon2; - - public Argon2() { - argon2 = Argon2Factory.create(); - } - - /** - * Checks if the argon2 library is available in java.library.path. - * - * @return true if the library is present, false otherwise - */ - public static boolean isLibraryLoaded() { - try { - System.loadLibrary("argon2"); - return true; - } catch (UnsatisfiedLinkError e) { - logger.logException( - "Cannot find argon2 library: https://github.com/AuthMe/AuthMeReloaded/wiki/Argon2-as-Password-Hash", e); - } - return false; - } - - @Override - public String computeHash(String password) { - return argon2.hash(2, 65536, 1, password); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return argon2.verify(hashedPassword.getHash(), password); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/BCrypt.java deleted file mode 100644 index 5b75c89a..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/BCrypt.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt.Version; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; - -import javax.inject.Inject; - -/** - * BCrypt hash algorithm with configurable cost factor. - */ -public class BCrypt extends BCryptBasedHash { - - @Inject - public BCrypt(Settings settings) { - super(createHasher(settings)); - } - - private static BCryptHasher createHasher(Settings settings) { - int bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND); - return new BCryptHasher(Version.VERSION_2A, bCryptLog2Rounds); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCrypt2y.java b/src/main/java/fr/xephi/authme/security/crypts/BCrypt2y.java deleted file mode 100644 index 2558fa98..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/BCrypt2y.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt; - -import javax.inject.Inject; - -/** - * Hash for BCrypt in the $2y$ variant. Uses a fixed cost factor of 10. - */ -public class BCrypt2y extends BCryptBasedHash { - - @Inject - public BCrypt2y() { - this(10); - } - - public BCrypt2y(int cost) { - super(new BCryptHasher(BCrypt.Version.VERSION_2Y, cost)); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCryptBasedHash.java b/src/main/java/fr/xephi/authme/security/crypts/BCryptBasedHash.java deleted file mode 100644 index 919c9bf2..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/BCryptBasedHash.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.crypts.BCryptHasher.SALT_LENGTH_ENCODED; -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * Abstract parent for BCrypt-based hash algorithms. - */ -@Recommendation(Usage.RECOMMENDED) -@HasSalt(value = SaltType.TEXT, length = SALT_LENGTH_ENCODED) -public abstract class BCryptBasedHash implements EncryptionMethod { - - private final BCryptHasher bCryptHasher; - - public BCryptBasedHash(BCryptHasher bCryptHasher) { - this.bCryptHasher = bCryptHasher; - } - - @Override - public HashedPassword computeHash(String password, String name) { - return bCryptHasher.hash(password); - } - - @Override - public String computeHash(String password, String salt, String name) { - return bCryptHasher.hashWithRawSalt(password, salt.getBytes(UTF_8)); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return BCryptHasher.comparePassword(password, hashedPassword.getHash()); - } - - @Override - public String generateSalt() { - return BCryptHasher.generateSalt(); - } - - @Override - public boolean hasSeparateSalt() { - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCryptHasher.java b/src/main/java/fr/xephi/authme/security/crypts/BCryptHasher.java deleted file mode 100644 index ffa1064d..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/BCryptHasher.java +++ /dev/null @@ -1,78 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt; -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.util.RandomStringUtils; - -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * Wraps a {@link BCrypt.Hasher} instance and provides methods suitable for use in AuthMe. - */ -public class BCryptHasher { - - /** Number of bytes in a BCrypt salt (not encoded). */ - public static final int BYTES_IN_SALT = 16; - /** Number of characters of the salt in its radix64-encoded form. */ - public static final int SALT_LENGTH_ENCODED = 22; - - private final BCrypt.Hasher hasher; - private final int costFactor; - - /** - * Constructor. - * - * @param version the BCrypt version the instance should generate - * @param costFactor the log2 cost factor to use - */ - public BCryptHasher(BCrypt.Version version, int costFactor) { - this.hasher = BCrypt.with(version); - this.costFactor = costFactor; - } - - public HashedPassword hash(String password) { - byte[] hash = hasher.hash(costFactor, password.getBytes(UTF_8)); - return new HashedPassword(new String(hash, UTF_8)); - } - - public String hashWithRawSalt(String password, byte[] rawSalt) { - byte[] hash = hasher.hash(costFactor, rawSalt, password.getBytes(UTF_8)); - return new String(hash, UTF_8); - } - - /** - * Verifies that the given password is correct for the provided BCrypt hash. - * - * @param password the password to check with - * @param hash the hash to check against - * @return true if the password matches the hash, false otherwise - */ - public static boolean comparePassword(String password, String hash) { - if (HashUtils.isValidBcryptHash(hash)) { - BCrypt.Result result = BCrypt.verifyer().verify(password.getBytes(UTF_8), hash.getBytes(UTF_8)); - return result.verified; - } - return false; - } - - /** - * Generates a salt for usage in BCrypt. The returned salt is not yet encoded. - *

- * Internally, the BCrypt library in {@link BCrypt.Hasher#hash(int, byte[])} uses the following: - * {@code Bytes.random(16, secureRandom).encodeUtf8();} - *

- * Because our {@link EncryptionMethod} interface works with {@code String} types we need to make sure that the - * generated bytes in the salt are suitable for conversion into a String, such that calling String#getBytes will - * yield the same number of bytes again. Thus, we are forced to limit the range of characters we use. Ideally we'd - * only have to pass the salt in its encoded form so that we could make use of the entire "spectrum" of values, - * which proves difficult to achieve with the underlying BCrypt library. However, the salt needs to be generated - * manually only for testing purposes; production code should always hash passwords using - * {@link EncryptionMethod#computeHash(String, String)}, which internally may represent salts in more suitable - * formats. - * - * @return the salt for a BCrypt hash - */ - public static String generateSalt() { - return RandomStringUtils.generateLowerUpper(BYTES_IN_SALT); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java deleted file mode 100644 index 2b94dc03..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; - -/** - * Hash algorithm to hook into the CMS Craft My Website. - */ -public class CmwCrypt extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return HashUtils.md5(HashUtils.sha1(password)); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/CrazyCrypt1.java b/src/main/java/fr/xephi/authme/security/crypts/CrazyCrypt1.java deleted file mode 100644 index 6130c6a1..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/CrazyCrypt1.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.MessageDigestAlgorithm; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; - -public class CrazyCrypt1 extends UsernameSaltMethod { - - private static final char[] CRYPTCHARS = - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - private static String byteArrayToHexString(final byte... args) { - final char[] chars = new char[args.length * 2]; - for (int i = 0; i < args.length; i++) { - chars[i * 2] = CRYPTCHARS[(args[i] >> 4) & 0xF]; - chars[i * 2 + 1] = CRYPTCHARS[(args[i]) & 0xF]; - } - return new String(chars); - } - - @Override - public HashedPassword computeHash(String password, String name) { - final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password; - final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512); - md.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length()); - return new HashedPassword(byteArrayToHexString(md.digest())); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/DoubleMd5.java b/src/main/java/fr/xephi/authme/security/crypts/DoubleMd5.java deleted file mode 100644 index 12e96808..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/DoubleMd5.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.HashUtils.md5; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class DoubleMd5 extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return md5(md5(password)); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java b/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java deleted file mode 100644 index 83cc6c8c..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/EncryptionMethod.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.security.crypts; - -/** - * Public interface for custom password encryption methods. - *

- * Instantiation of these methods is done via automatic dependency injection. - */ -public interface EncryptionMethod { - - /** - * Hash the given password for the given player name. - * - * @param password The password to hash - * @param name The name of the player (sometimes required to generate a salt with) - * - * @return The hash result for the password. - * @see HashedPassword - */ - HashedPassword computeHash(String password, String name); - - /** - * Hash the given password with the given salt for the given player. - * - * @param password The password to hash - * @param salt The salt to add to the hash - * @param name The player's name (sometimes required to generate a salt with) - * - * @return The hashed password - * @see #hasSeparateSalt() - */ - String computeHash(String password, String salt, String name); - - /** - * Check whether the given hash matches the clear-text password. - * - * @param password The clear-text password to verify - * @param hashedPassword The hash to check the password against - * @param name The player name to do the check for (sometimes required for generating the salt) - * - * @return True if the password matches, false otherwise - */ - boolean comparePassword(String password, HashedPassword hashedPassword, String name); - - /** - * Generate a new salt to hash a password with. - * - * @return The generated salt, null if the method does not use a random text-based salt - */ - String generateSalt(); - - /** - * Return whether the encryption method requires the salt to be stored separately and - * passed again to {@link #comparePassword(String, HashedPassword, String)}. Note that - * an encryption method returning {@code false} does not imply that it uses no salt; it - * may be embedded into the hash or it may use the username as salt. - * - * @return True if the salt has to be stored and retrieved separately, false otherwise - */ - boolean hasSeparateSalt(); - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/HashedPassword.java b/src/main/java/fr/xephi/authme/security/crypts/HashedPassword.java deleted file mode 100644 index f2e40aa4..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/HashedPassword.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.security.crypts; - -/** - * The result of a hash computation. See {@link #salt} for details. - */ -public class HashedPassword { - - /** The generated hash. */ - private final String hash; - /** - * The generated salt; may be null if no salt is used or if the salt is included - * in the hash output. The salt is only not null if {@link EncryptionMethod#hasSeparateSalt()} - * returns true for the associated encryption method. - *

- * When the field is not null, it must be stored into the salt column of the data source - * and retrieved again to compare a password with the hash. - */ - private final String salt; - - /** - * Constructor. - * - * @param hash The computed hash - * @param salt The generated salt - */ - public HashedPassword(String hash, String salt) { - this.hash = hash; - this.salt = salt; - } - - /** - * Constructor for a hash with no separate salt. - * - * @param hash The computed hash - */ - public HashedPassword(String hash) { - this(hash, null); - } - - public String getHash() { - return hash; - } - - public String getSalt() { - return salt; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java b/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java deleted file mode 100644 index 81e76772..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/HexSaltedMethod.java +++ /dev/null @@ -1,40 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -/** - * Common type for encryption methods which use a random String of hexadecimal characters - * and store the salt with the hash itself. - */ -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(SaltType.TEXT) // See getSaltLength() for length -public abstract class HexSaltedMethod implements EncryptionMethod { - - public abstract int getSaltLength(); - - @Override - public abstract String computeHash(String password, String salt, String name); - - @Override - public HashedPassword computeHash(String password, String name) { - String salt = generateSalt(); - return new HashedPassword(computeHash(password, salt, null)); - } - - @Override - public abstract boolean comparePassword(String password, HashedPassword hashedPassword, String name); - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(getSaltLength()); - } - - @Override - public boolean hasSeparateSalt() { - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Ipb3.java b/src/main/java/fr/xephi/authme/security/crypts/Ipb3.java deleted file mode 100644 index b29df4fc..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Ipb3.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import static fr.xephi.authme.security.HashUtils.md5; - -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(value = SaltType.TEXT, length = 5) -public class Ipb3 extends SeparateSaltMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return md5(md5(salt) + md5(password)); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(5); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Ipb4.java b/src/main/java/fr/xephi/authme/security/crypts/Ipb4.java deleted file mode 100644 index e176d0aa..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Ipb4.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt; -import at.favre.lib.crypto.bcrypt.IllegalBCryptFormatException; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import static java.nio.charset.StandardCharsets.UTF_8; - - -/** - * Implementation for Ipb4 (Invision Power Board 4). - *

- * The hash uses standard BCrypt with 13 as log2 number of rounds. Additionally, - * Ipb4 requires that the salt be stored in the column "members_pass_hash" as well - * (even though BCrypt hashes already contain the salt within themselves). - */ -@Recommendation(Usage.DOES_NOT_WORK) -@HasSalt(value = SaltType.TEXT, length = BCryptHasher.SALT_LENGTH_ENCODED) -public class Ipb4 implements EncryptionMethod { - - private BCryptHasher bCryptHasher = new BCryptHasher(BCrypt.Version.VERSION_2A, 13); - - @Override - public String computeHash(String password, String salt, String name) { - // Since the radix64-encoded salt is necessary to be stored separately as well, the incoming salt here is - // radix64-encoded (see #generateSalt()). This means we first need to decode it before passing into the - // bcrypt hasher... We cheat by inserting the encoded salt into a dummy bcrypt hash so that we can parse it - // with the BCrypt utilities. - // This method (with specific salt) is only used for testing purposes, so this approach should be OK. - - String dummyHash = "$2a$10$" + salt + "3Cfb5GnwvKhJ20r.hMjmcNkIT9.Uh9K"; - try { - BCrypt.HashData parseResult = BCrypt.Version.VERSION_2A.parser.parse(dummyHash.getBytes(UTF_8)); - return bCryptHasher.hashWithRawSalt(password, parseResult.rawSalt); - } catch (IllegalBCryptFormatException |IllegalArgumentException e) { - throw new IllegalStateException("Cannot parse hash with salt '" + salt + "'", e); - } - } - - @Override - public HashedPassword computeHash(String password, String name) { - HashedPassword hash = bCryptHasher.hash(password); - - // 7 chars prefix, then 22 chars which is the encoded salt, which we need again - String salt = hash.getHash().substring(7, 29); - return new HashedPassword(hash.getHash(), salt); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return BCryptHasher.comparePassword(password, hashedPassword.getHash()); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateLowerUpper(22); - } - - @Override - public boolean hasSeparateSalt() { - return true; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Joomla.java b/src/main/java/fr/xephi/authme/security/crypts/Joomla.java deleted file mode 100644 index 2ecc1d8d..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Joomla.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -@Recommendation(Usage.ACCEPTABLE) -public class Joomla extends HexSaltedMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return HashUtils.md5(password + salt) + ":" + salt; - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) { - String hash = hashedPassword.getHash(); - String[] hashParts = hash.split(":"); - return hashParts.length == 2 && isEqual(hash, computeHash(password, hashParts[1], null)); - } - - @Override - public int getSaltLength() { - return 32; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Md5.java b/src/main/java/fr/xephi/authme/security/crypts/Md5.java deleted file mode 100644 index 55e07a17..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Md5.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class Md5 extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return HashUtils.md5(password); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Md5vB.java b/src/main/java/fr/xephi/authme/security/crypts/Md5vB.java deleted file mode 100644 index 00656964..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Md5vB.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import static fr.xephi.authme.security.HashUtils.isEqual; -import static fr.xephi.authme.security.HashUtils.md5; - -public class Md5vB extends HexSaltedMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return "$MD5vb$" + salt + "$" + md5(md5(password) + salt); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - String hash = hashedPassword.getHash(); - String[] line = hash.split("\\$"); - return line.length == 4 && isEqual(hash, computeHash(password, line[2], name)); - } - - @Override - public int getSaltLength() { - return 16; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/MyBB.java b/src/main/java/fr/xephi/authme/security/crypts/MyBB.java deleted file mode 100644 index 3ff0ee5e..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/MyBB.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import static fr.xephi.authme.security.HashUtils.md5; - -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(value = SaltType.TEXT, length = 8) -@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) -public class MyBB extends SeparateSaltMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return md5(md5(salt) + md5(password)); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateLowerUpper(8); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/NoCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/NoCrypt.java deleted file mode 100644 index afd298ec..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/NoCrypt.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class NoCrypt extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return password; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java deleted file mode 100644 index c79647ab..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import com.google.common.primitives.Ints; -import de.rtner.misc.BinTools; -import de.rtner.security.auth.spi.PBKDF2Engine; -import de.rtner.security.auth.spi.PBKDF2Parameters; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; - -import javax.inject.Inject; - -@Recommendation(Usage.RECOMMENDED) -public class Pbkdf2 extends HexSaltedMethod { - - private static final int DEFAULT_ROUNDS = 10_000; - private final ConsoleLogger logger = ConsoleLoggerFactory.get(Pbkdf2.class); - private int numberOfRounds; - - @Inject - Pbkdf2(Settings settings) { - int configuredRounds = settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS); - this.numberOfRounds = configuredRounds > 0 ? configuredRounds : DEFAULT_ROUNDS; - } - - @Override - public String computeHash(String password, String salt, String name) { - String result = "pbkdf2_sha256$" + numberOfRounds + "$" + salt + "$"; - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), numberOfRounds); - PBKDF2Engine engine = new PBKDF2Engine(params); - - return result + BinTools.bin2hex(engine.deriveKey(password, 64)); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) { - String[] line = hashedPassword.getHash().split("\\$"); - if (line.length != 4) { - return false; - } - Integer iterations = Ints.tryParse(line[1]); - if (iterations == null) { - logger.warning("Cannot read number of rounds for Pbkdf2: '" + line[1] + "'"); - return false; - } - - String salt = line[2]; - byte[] derivedKey = BinTools.hex2bin(line[3]); - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), iterations, derivedKey); - PBKDF2Engine engine = new PBKDF2Engine(params); - return engine.verifyKey(password); - } - - @Override - public int getSaltLength() { - return 16; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java deleted file mode 100644 index a0877cd4..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import com.google.common.primitives.Ints; -import de.rtner.security.auth.spi.PBKDF2Engine; -import de.rtner.security.auth.spi.PBKDF2Parameters; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.description.AsciiRestricted; - -import java.util.Base64; - -@AsciiRestricted -public class Pbkdf2Django extends HexSaltedMethod { - - private static final int DEFAULT_ITERATIONS = 24000; - private final ConsoleLogger logger = ConsoleLoggerFactory.get(Pbkdf2Django.class); - - @Override - public String computeHash(String password, String salt, String name) { - String result = "pbkdf2_sha256$" + DEFAULT_ITERATIONS + "$" + salt + "$"; - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), DEFAULT_ITERATIONS); - PBKDF2Engine engine = new PBKDF2Engine(params); - - return result + Base64.getEncoder().encodeToString(engine.deriveKey(password, 32)); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) { - String[] line = hashedPassword.getHash().split("\\$"); - if (line.length != 4) { - return false; - } - Integer iterations = Ints.tryParse(line[1]); - if (iterations == null) { - logger.warning("Cannot read number of rounds for Pbkdf2Django: '" + line[1] + "'"); - return false; - } - - String salt = line[2]; - byte[] derivedKey = Base64.getDecoder().decode(line[3]); - PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), iterations, derivedKey); - PBKDF2Engine engine = new PBKDF2Engine(params); - return engine.verifyKey(password); - } - - @Override - public int getSaltLength() { - return 12; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/PhpBB.java b/src/main/java/fr/xephi/authme/security/crypts/PhpBB.java deleted file mode 100644 index c4e27e9d..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/PhpBB.java +++ /dev/null @@ -1,162 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.MessageDigestAlgorithm; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; - -import static fr.xephi.authme.security.HashUtils.isEqual; -import static fr.xephi.authme.security.crypts.BCryptHasher.SALT_LENGTH_ENCODED; - -/** - * Encryption method compatible with phpBB3. - *

- * As tested with phpBB 3.2.1, by default new passwords are encrypted with BCrypt $2y$. - * For backwards compatibility, phpBB3 supports other hashes for comparison. This implementation - * successfully checks against phpBB's salted MD5 hashing algorithm (adaptation of phpass), - * as well as plain MD5. - */ -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(value = SaltType.TEXT, length = SALT_LENGTH_ENCODED) -public class PhpBB implements EncryptionMethod { - - private final BCrypt2y bCrypt2y = new BCrypt2y(); - - @Override - public HashedPassword computeHash(String password, String name) { - return bCrypt2y.computeHash(password, name); - } - - @Override - public String computeHash(String password, String salt, String name) { - return bCrypt2y.computeHash(password, salt, name); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - final String hash = hashedPassword.getHash(); - if (HashUtils.isValidBcryptHash(hash)) { - return bCrypt2y.comparePassword(password, hashedPassword, name); - } else if (hash.length() == 34) { - return PhpassSaltedMd5.phpbb_check_hash(password, hash); - } else { - return isEqual(hash, PhpassSaltedMd5.md5(password)); - } - } - - @Override - public String generateSalt() { - // Salt length 22, as seen in https://github.com/phpbb/phpbb/blob/master/phpBB/phpbb/passwords/driver/bcrypt.php - // Ours generates 16 chars because the salt must not yet be encoded. - return BCryptHasher.generateSalt(); - } - - @Override - public boolean hasSeparateSalt() { - return false; - } - - /** - * Java implementation of the salted MD5 as used in phpBB (adapted from phpass). - * - * @see phpBB's salted_md5.php - * @see phpass - */ - private static final class PhpassSaltedMd5 { - - private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - private static String md5(String data) { - try { - byte[] bytes = data.getBytes("ISO-8859-1"); - MessageDigest md5er = HashUtils.getDigest(MessageDigestAlgorithm.MD5); - byte[] hash = md5er.digest(bytes); - return bytes2hex(hash); - } catch (UnsupportedEncodingException e) { - throw new UnsupportedOperationException(e); - } - } - - private static int hexToInt(char ch) { - if (ch >= '0' && ch <= '9') - return ch - '0'; - ch = Character.toUpperCase(ch); - if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 0xA; - throw new IllegalArgumentException("Not a hex character: " + ch); - } - - private static String bytes2hex(byte[] bytes) { - StringBuilder r = new StringBuilder(32); - for (byte b : bytes) { - String x = Integer.toHexString(b & 0xff); - if (x.length() < 2) - r.append('0'); - r.append(x); - } - return r.toString(); - } - - private static String pack(String hex) { - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < hex.length(); i += 2) { - char c1 = hex.charAt(i); - char c2 = hex.charAt(i + 1); - char packed = (char) (hexToInt(c1) * 16 + hexToInt(c2)); - buf.append(packed); - } - return buf.toString(); - } - - private static String _hash_encode64(String input, int count) { - StringBuilder output = new StringBuilder(); - int i = 0; - do { - int value = input.charAt(i++); - output.append(itoa64.charAt(value & 0x3f)); - if (i < count) - value |= input.charAt(i) << 8; - output.append(itoa64.charAt((value >> 6) & 0x3f)); - if (i++ >= count) - break; - if (i < count) - value |= input.charAt(i) << 16; - output.append(itoa64.charAt((value >> 12) & 0x3f)); - if (i++ >= count) - break; - output.append(itoa64.charAt((value >> 18) & 0x3f)); - } while (i < count); - return output.toString(); - } - - private static String _hash_crypt_private(String password, String setting) { - String output = "*"; - if (!setting.substring(0, 3).equals("$H$")) - return output; - int count_log2 = itoa64.indexOf(setting.charAt(3)); - if (count_log2 < 7 || count_log2 > 30) - return output; - int count = 1 << count_log2; - String salt = setting.substring(4, 12); - if (salt.length() != 8) - return output; - String m1 = md5(salt + password); - String hash = pack(m1); - do { - hash = pack(md5(hash + password)); - } while (--count > 0); - output = setting.substring(0, 12); - output += _hash_encode64(hash, 16); - return output; - } - - private static boolean phpbb_check_hash(String password, String hash) { - return isEqual(hash, _hash_crypt_private(password, hash)); // #1561: fix timing issue - } - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/PhpFusion.java b/src/main/java/fr/xephi/authme/security/crypts/PhpFusion.java deleted file mode 100644 index b9744117..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/PhpFusion.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.AsciiRestricted; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import java.io.UnsupportedEncodingException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -@Recommendation(Usage.DO_NOT_USE) -@AsciiRestricted -public class PhpFusion extends SeparateSaltMethod { - - @Override - public String computeHash(String password, String salt, String name) { - String algo = "HmacSHA256"; - String keyString = HashUtils.sha1(salt); - try { - SecretKeySpec key = new SecretKeySpec(keyString.getBytes("UTF-8"), algo); - Mac mac = Mac.getInstance(algo); - mac.init(key); - byte[] bytes = mac.doFinal(password.getBytes("ASCII")); - StringBuilder hash = new StringBuilder(); - for (byte aByte : bytes) { - String hex = Integer.toHexString(0xFF & aByte); - if (hex.length() == 1) { - hash.append('0'); - } - hash.append(hex); - } - return hash.toString(); - } catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) { - throw new UnsupportedOperationException("Cannot create PHPFUSION hash for " + name, e); - } - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(12); - } - - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java b/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java deleted file mode 100644 index 9f557438..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.MessageDigestAlgorithm; - -import java.security.MessageDigest; - -public class RoyalAuth extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - MessageDigest algorithm = HashUtils.getDigest(MessageDigestAlgorithm.SHA512); - for (int i = 0; i < 25; ++i) { - password = HashUtils.hash(password, algorithm); - } - return password; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Salted2Md5.java b/src/main/java/fr/xephi/authme/security/crypts/Salted2Md5.java deleted file mode 100644 index 3d2166a7..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Salted2Md5.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.RandomStringUtils; - -import javax.inject.Inject; - -import static fr.xephi.authme.security.HashUtils.md5; - -@Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8) -@HasSalt(value = SaltType.TEXT) // length defined by the doubleMd5SaltLength setting -public class Salted2Md5 extends SeparateSaltMethod { - - private final int saltLength; - - @Inject - public Salted2Md5(Settings settings) { - saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH); - } - - @Override - public String computeHash(String password, String salt, String name) { - return md5(md5(password) + salt); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(saltLength); - } - - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/SaltedSha512.java b/src/main/java/fr/xephi/authme/security/crypts/SaltedSha512.java deleted file mode 100644 index b5578b93..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/SaltedSha512.java +++ /dev/null @@ -1,20 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -@Recommendation(Usage.RECOMMENDED) -public class SaltedSha512 extends SeparateSaltMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return HashUtils.sha512(password + salt); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(32); - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java b/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java deleted file mode 100644 index c0ec13dd..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/SeparateSaltMethod.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -/** - * Common supertype for encryption methods which store their salt separately from the hash. - */ -public abstract class SeparateSaltMethod implements EncryptionMethod { - - @Override - public abstract String computeHash(String password, String salt, String name); - - @Override - public HashedPassword computeHash(String password, String name) { - String salt = generateSalt(); - return new HashedPassword(computeHash(password, salt, name), salt); - } - - @Override - public abstract String generateSalt(); - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return isEqual(hashedPassword.getHash(), computeHash(password, hashedPassword.getSalt(), null)); - } - - @Override - public boolean hasSeparateSalt() { - return true; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Sha1.java b/src/main/java/fr/xephi/authme/security/crypts/Sha1.java deleted file mode 100644 index 6d095b4a..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Sha1.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class Sha1 extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return HashUtils.sha1(password); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Sha256.java b/src/main/java/fr/xephi/authme/security/crypts/Sha256.java deleted file mode 100644 index ce6b2549..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Sha256.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.HashUtils.isEqual; -import static fr.xephi.authme.security.HashUtils.sha256; - -@Recommendation(Usage.RECOMMENDED) -public class Sha256 extends HexSaltedMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return "$SHA$" + salt + "$" + sha256(sha256(password) + salt); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - String hash = hashedPassword.getHash(); - String[] line = hash.split("\\$"); - return line.length == 4 && isEqual(hash, computeHash(password, line[2], name)); - } - - @Override - public int getSaltLength() { - return 16; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Sha512.java b/src/main/java/fr/xephi/authme/security/crypts/Sha512.java deleted file mode 100644 index 36dc5a34..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Sha512.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class Sha512 extends UnsaltedMethod { - - @Override - public String computeHash(String password) { - return HashUtils.sha512(password); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Smf.java b/src/main/java/fr/xephi/authme/security/crypts/Smf.java deleted file mode 100644 index 19193d63..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Smf.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import java.util.Locale; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -/** - * Hashing algorithm for SMF forums. - *

- * The hash algorithm is {@code sha1(strtolower($username) . $password)}. However, an additional four-character - * salt is generated for each user, used to generate the login cookie. Therefore, this implementation generates a salt - * and declares that it requires a separate salt (the SMF members table has a not-null constraint on the salt column). - * - * @see Simple Machines Forum - */ -@Recommendation(Usage.DO_NOT_USE) -@HasSalt(SaltType.USERNAME) -public class Smf implements EncryptionMethod { - - @Override - public HashedPassword computeHash(String password, String name) { - return new HashedPassword(computeHash(password, null, name), generateSalt()); - } - - @Override - public String computeHash(String password, String salt, String name) { - return HashUtils.sha1(name.toLowerCase(Locale.ROOT) + password); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return isEqual(hashedPassword.getHash(), computeHash(password, null, name)); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generate(4); - } - - @Override - public boolean hasSeparateSalt() { - return true; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java b/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java deleted file mode 100644 index 67b22c78..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/TwoFactor.java +++ /dev/null @@ -1,140 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import com.google.common.escape.Escaper; -import com.google.common.io.BaseEncoding; -import com.google.common.net.UrlEscapers; -import com.google.common.primitives.Ints; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Calendar; -import java.util.concurrent.TimeUnit; - -/** - * Two factor authentication. - * - * @see Original source - */ -@Recommendation(Usage.DOES_NOT_WORK) -@HasSalt(SaltType.NONE) -public class TwoFactor extends UnsaltedMethod { - - private static final int SCRET_BYTE = 10; - private static final int SCRATCH_CODES = 5; - private static final int BYTES_PER_SCRATCH_CODE = 4; - - private static final int TIME_PRECISION = 3; - private static final String CRYPTO_ALGO = "HmacSHA1"; - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TwoFactor.class); - - /** - * Creates a link to a QR barcode with the provided secret. - * - * @param user the player's name - * @param host the server host - * @param secret the TOTP secret - * @return URL leading to a QR code - */ - public static String getQrBarcodeUrl(String user, String host, String secret) { - String format = "https://www.google.com/chart?chs=130x130&chld=M%%7C0&cht=qr&chl=" - + "otpauth://totp/" - + "%s@%s%%3Fsecret%%3D%s"; - Escaper urlEscaper = UrlEscapers.urlFragmentEscaper(); - return String.format(format, urlEscaper.escape(user), urlEscaper.escape(host), secret); - } - - @Override - public String computeHash(String password) { - // Allocating the buffer - byte[] buffer = new byte[SCRET_BYTE + SCRATCH_CODES * BYTES_PER_SCRATCH_CODE]; - - // Filling the buffer with random numbers. - // Notice: you want to reuse the same random generator - // while generating larger random number sequences. - new SecureRandom().nextBytes(buffer); - - // Getting the key and converting it to Base32 - byte[] secretKey = Arrays.copyOf(buffer, SCRET_BYTE); - return BaseEncoding.base32().encode(secretKey); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - try { - return checkPassword(hashedPassword.getHash(), password); - } catch (Exception e) { - logger.logException("Failed to verify two auth code:", e); - return false; - } - } - - private boolean checkPassword(String secretKey, String userInput) - throws NoSuchAlgorithmException, InvalidKeyException { - Integer code = Ints.tryParse(userInput); - if (code == null) { - //code is not an integer - return false; - } - - long currentTime = Calendar.getInstance().getTimeInMillis() / TimeUnit.SECONDS.toMillis(30); - return checkCode(secretKey, code, currentTime); - } - - private boolean checkCode(String secret, long code, long t) throws NoSuchAlgorithmException, InvalidKeyException { - byte[] decodedKey = BaseEncoding.base32().decode(secret); - - // Window is used to check codes generated in the near past. - // You can use this value to tune how far you're willing to go. - int window = TIME_PRECISION; - for (int i = -window; i <= window; ++i) { - long hash = verifyCode(decodedKey, t + i); - - if (hash == code) { - return true; - } - } - - // The validation code is invalid. - return false; - } - - private int verifyCode(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException { - byte[] data = new byte[8]; - long value = t; - for (int i = 8; i-- > 0; value >>>= 8) { - data[i] = (byte) value; - } - - SecretKeySpec signKey = new SecretKeySpec(key, CRYPTO_ALGO); - Mac mac = Mac.getInstance(CRYPTO_ALGO); - mac.init(signKey); - byte[] hash = mac.doFinal(data); - - int offset = hash[20 - 1] & 0xF; - - // We're using a long because Java hasn't got unsigned int. - long truncatedHash = 0; - for (int i = 0; i < 4; ++i) { - truncatedHash <<= 8; - // We are dealing with signed bytes: - // we just keep the first byte. - truncatedHash |= (hash[offset + i] & 0xFF); - } - - truncatedHash &= 0x7FFF_FFFF; - truncatedHash %= 1_000_000; - - return (int) truncatedHash; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java b/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java deleted file mode 100644 index 33815ec7..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/UnsaltedMethod.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -/** - * Common type for encryption methods which do not use any salt whatsoever. - */ -@Recommendation(Usage.DO_NOT_USE) -@HasSalt(SaltType.NONE) -public abstract class UnsaltedMethod implements EncryptionMethod { - - public abstract String computeHash(String password); - - @Override - public HashedPassword computeHash(String password, String name) { - return new HashedPassword(computeHash(password)); - } - - @Override - public String computeHash(String password, String salt, String name) { - return computeHash(password); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return isEqual(hashedPassword.getHash(), computeHash(password)); - } - - @Override - public String generateSalt() { - return null; - } - - @Override - public boolean hasSeparateSalt() { - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java b/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java deleted file mode 100644 index f5930fcf..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/UsernameSaltMethod.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -/** - * Common supertype of encryption methods that use a player's username - * (or something based on it) as embedded salt. - */ -@Recommendation(Usage.DO_NOT_USE) -@HasSalt(SaltType.USERNAME) -public abstract class UsernameSaltMethod implements EncryptionMethod { - - @Override - public abstract HashedPassword computeHash(String password, String name); - - @Override - public String computeHash(String password, String salt, String name) { - return computeHash(password, name).getHash(); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - return isEqual(hashedPassword.getHash(), computeHash(password, name).getHash()); - } - - @Override - public String generateSalt() { - return null; - } - - @Override - public boolean hasSeparateSalt() { - return false; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Wbb3.java b/src/main/java/fr/xephi/authme/security/crypts/Wbb3.java deleted file mode 100644 index 8e26463b..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Wbb3.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; -import fr.xephi.authme.util.RandomStringUtils; - -import static fr.xephi.authme.security.HashUtils.sha1; - -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(value = SaltType.TEXT, length = 40) -public class Wbb3 extends SeparateSaltMethod { - - @Override - public String computeHash(String password, String salt, String name) { - return sha1(salt.concat(sha1(salt.concat(sha1(password))))); - } - - @Override - public String generateSalt() { - return RandomStringUtils.generateHex(40); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Wbb4.java b/src/main/java/fr/xephi/authme/security/crypts/Wbb4.java deleted file mode 100644 index a55a2d48..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Wbb4.java +++ /dev/null @@ -1,74 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt; -import at.favre.lib.crypto.bcrypt.IllegalBCryptFormatException; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import java.security.SecureRandom; - -import static fr.xephi.authme.security.HashUtils.isEqual; -import static fr.xephi.authme.security.crypts.BCryptHasher.BYTES_IN_SALT; -import static fr.xephi.authme.security.crypts.BCryptHasher.SALT_LENGTH_ENCODED; -import static java.nio.charset.StandardCharsets.UTF_8; - -@Recommendation(Usage.RECOMMENDED) -@HasSalt(value = SaltType.TEXT, length = SALT_LENGTH_ENCODED) -public class Wbb4 implements EncryptionMethod { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(Wbb4.class); - private BCryptHasher bCryptHasher = new BCryptHasher(BCrypt.Version.VERSION_2A, 8); - private SecureRandom random = new SecureRandom(); - - @Override - public HashedPassword computeHash(String password, String name) { - byte[] salt = new byte[BYTES_IN_SALT]; - random.nextBytes(salt); - - String hash = hashInternal(password, salt); - return new HashedPassword(hash); - } - - @Override - public String computeHash(String password, String salt, String name) { - return hashInternal(password, salt.getBytes(UTF_8)); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - try { - BCrypt.HashData hashData = BCrypt.Version.VERSION_2A.parser.parse(hashedPassword.getHash().getBytes(UTF_8)); - byte[] salt = hashData.rawSalt; - String computedHash = hashInternal(password, salt); - return isEqual(hashedPassword.getHash(), computedHash); - } catch (IllegalBCryptFormatException | IllegalArgumentException e) { - logger.logException("Invalid WBB4 hash:", e); - } - return false; - } - - /** - * Hashes the given password with the provided salt twice: hash(hash(password, salt), salt). - * - * @param password the password to hash - * @param rawSalt the salt to use - * @return WBB4-compatible hash - */ - private String hashInternal(String password, byte[] rawSalt) { - return bCryptHasher.hashWithRawSalt(bCryptHasher.hashWithRawSalt(password, rawSalt), rawSalt); - } - - @Override - public String generateSalt() { - return BCryptHasher.generateSalt(); - } - - @Override - public boolean hasSeparateSalt() { - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Whirlpool.java b/src/main/java/fr/xephi/authme/security/crypts/Whirlpool.java deleted file mode 100644 index 1a450d56..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Whirlpool.java +++ /dev/null @@ -1,399 +0,0 @@ -package fr.xephi.authme.security.crypts; - -/** - * The Whirlpool hashing function. - *

- *

- * References - *

- *

- * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and Vincent Rijmen. - *

- * See P.S.L.M. Barreto, V. Rijmen, ``The Whirlpool hashing function,'' First - * NESSIE workshop, 2000 (tweaked version, 2003), - * - * - * @author Paulo S.L.M. Barreto - * @author Vincent Rijmen. - * @version 3.0 (2003.03.12) - *

- * ==================================================================== - * ========= - *

- * Differences from version 2.1: - *

- * - Suboptimal diffusion matrix replaced by cir(1, 1, 4, 1, 8, 5, 2, - * 9). - *

- * ==================================================================== - * ========= - *

- * Differences from version 2.0: - *

- * - Generation of ISO/IEC 10118-3 test vectors. - Bug fix: nonzero - * carry was ignored when tallying the data length (this bug apparently - * only manifested itself when feeding data in pieces rather than in a - * single chunk at once). - *

- * Differences from version 1.0: - *

- * - Original S-box replaced by the tweaked, hardware-efficient - * version. - *

- * ==================================================================== - * ========= - *

- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -import java.util.Arrays; - -@Deprecated -@Recommendation(Usage.DEPRECATED) -public class Whirlpool extends UnsaltedMethod { - - /** - * The message digest size (in bits) - */ - public static final int DIGESTBITS = 512; - - /** - * The message digest size (in bytes) - */ - public static final int DIGESTBYTES = DIGESTBITS >>> 3; - - /** - * The number of rounds of the internal dedicated block cipher. - */ - protected static final int R = 10; - - /** - * The substitution box. - */ - private static final String sbox = "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" + "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" + "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" + "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" + "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" + "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" + "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" + "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" + "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" + "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" + "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" + "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" + "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" + "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" + "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" + "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886"; - - private static final long[][] C = new long[8][256]; - private static final long[] rc = new long[R + 1]; - - static { - for (int x = 0; x < 256; x++) { - char c = sbox.charAt(x / 2); - long v1 = ((x & 1) == 0) ? c >>> 8 : c & 0xff; - long v2 = v1 << 1; - if (v2 >= 0x100L) { - v2 ^= 0x11dL; - } - long v4 = v2 << 1; - if (v4 >= 0x100L) { - v4 ^= 0x11dL; - } - long v5 = v4 ^ v1; - long v8 = v4 << 1; - if (v8 >= 0x100L) { - v8 ^= 0x11dL; - } - long v9 = v8 ^ v1; - /* - * build the circulant table C[0][x] = S[x].[1, 1, 4, 1, 8, 5, 2, - * 9]: - */ - C[0][x] = (v1 << 56) | (v1 << 48) | (v4 << 40) | (v1 << 32) | (v8 << 24) | (v5 << 16) | (v2 << 8) | (v9); - /* - * build the remaining circulant tables C[t][x] = C[0][x] rotr t - */ - for (int t = 1; t < 8; t++) { - C[t][x] = (C[t - 1][x] >>> 8) | ((C[t - 1][x] << 56)); - } - } - /* - * build the round constants: - */ - rc[0] = 0L; /* - * not used (assigment kept only to properly initialize all - * variables) - */ - for (int r = 1; r <= R; r++) { - int i = 8 * (r - 1); - rc[r] = (C[0][i] & 0xff00000000000000L) ^ (C[1][i + 1] & 0x00ff000000000000L) ^ (C[2][i + 2] & 0x0000ff0000000000L) ^ (C[3][i + 3] & 0x000000ff00000000L) ^ (C[4][i + 4] & 0x00000000ff000000L) ^ (C[5][i + 5] & 0x0000000000ff0000L) ^ (C[6][i + 6] & 0x000000000000ff00L) ^ (C[7][i + 7] & 0x00000000000000ffL); - } - } - - /** - * Global number of hashed bits (256-bit counter). - */ - protected final byte[] bitLength = new byte[32]; - - /** - * Buffer of data to hash. - */ - protected final byte[] buffer = new byte[64]; - - /** - * Current number of bits on the buffer. - */ - protected int bufferBits = 0; - - /** - * Current (possibly incomplete) byte slot on the buffer. - */ - protected int bufferPos = 0; - - /** - * The hashing state. - */ - protected final long[] hash = new long[8]; - protected final long[] K = new long[8]; - protected final long[] L = new long[8]; - protected final long[] block = new long[8]; - protected final long[] state = new long[8]; - - public Whirlpool() { - } - - protected static String display(byte[] array) { - char[] val = new char[2 * array.length]; - String hex = "0123456789ABCDEF"; - for (int i = 0; i < array.length; i++) { - int b = array[i] & 0xff; - val[2 * i] = hex.charAt(b >>> 4); - val[2 * i + 1] = hex.charAt(b & 15); - } - return String.valueOf(val); - } - - /** - * The core Whirlpool transform. - */ - protected void processBuffer() { - /* - * map the buffer to a block: - */ - for (int i = 0, j = 0; i < 8; i++, j += 8) { - block[i] = (((long) buffer[j]) << 56) ^ (((long) buffer[j + 1] & 0xffL) << 48) ^ (((long) buffer[j + 2] & 0xffL) << 40) ^ (((long) buffer[j + 3] & 0xffL) << 32) ^ (((long) buffer[j + 4] & 0xffL) << 24) ^ (((long) buffer[j + 5] & 0xffL) << 16) ^ (((long) buffer[j + 6] & 0xffL) << 8) ^ (((long) buffer[j + 7] & 0xffL)); - } - /* - * compute and apply K^0 to the cipher state: - */ - for (int i = 0; i < 8; i++) { - state[i] = block[i] ^ (K[i] = hash[i]); - } - /* - * iterate over all rounds: - */ - for (int r = 1; r <= R; r++) { - /* - * compute K^r from K^{r-1}: - */ - for (int i = 0; i < 8; i++) { - L[i] = 0L; - for (int t = 0, s = 56; t < 8; t++, s -= 8) { - L[i] ^= C[t][(int) (K[(i - t) & 7] >>> s) & 0xff]; - } - } - for (int i = 0; i < 8; i++) { - K[i] = L[i]; - } - K[0] ^= rc[r]; - /* - * apply the r-th round transformation: - */ - for (int i = 0; i < 8; i++) { - L[i] = K[i]; - for (int t = 0, s = 56; t < 8; t++, s -= 8) { - L[i] ^= C[t][(int) (state[(i - t) & 7] >>> s) & 0xff]; - } - } - for (int i = 0; i < 8; i++) { - state[i] = L[i]; - } - } - /* - * apply the Miyaguchi-Preneel compression function: - */ - for (int i = 0; i < 8; i++) { - hash[i] ^= state[i] ^ block[i]; - } - } - - /** - * Initialize the hashing state. - */ - public void NESSIEinit() { - Arrays.fill(bitLength, (byte) 0); - bufferBits = bufferPos = 0; - buffer[0] = 0; - Arrays.fill(hash, 0L); - } - - /** - * Delivers input data to the hashing algorithm. - * - * @param source plaintext data to hash. - * @param sourceBits how many bits of plaintext to process. - *

- * This method maintains the invariant: bufferBits < 512 - *

- */ - public void NESSIEadd(byte[] source, long sourceBits) { - /* - * sourcePos | +-------+-------+------- ||||||||||||||||||||| source - * +-------+-------+------- - * +-------+-------+-------+-------+-------+------- - * |||||||||||||||||||||| buffer - * +-------+-------+-------+-------+-------+------- | bufferPos - */ - int sourcePos = 0; // index of leftmost source byte containing data (1 - // to 8 bits). - int sourceGap = (8 - ((int) sourceBits & 7)) & 7; // space on - // source[sourcePos]. - int bufferRem = bufferBits & 7; // occupied bits on buffer[bufferPos]. - int b; - // tally the length of the added data: - long value = sourceBits; - for (int i = 31, carry = 0; i >= 0; i--) { - carry += (bitLength[i] & 0xff) + ((int) value & 0xff); - bitLength[i] = (byte) carry; - carry >>>= 8; - value >>>= 8; - } - // process data in chunks of 8 bits: - while (sourceBits > 8) { // at least source[sourcePos] and - // source[sourcePos+1] contain data. - // take a byte from the source: - b = ((source[sourcePos] << sourceGap) & 0xff) | ((source[sourcePos + 1] & 0xff) >>> (8 - sourceGap)); - if (b < 0 || b >= 256) { - throw new RuntimeException("LOGIC ERROR"); - } - // process this byte: - buffer[bufferPos++] |= b >>> bufferRem; - bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos; - if (bufferBits == 512) { - // process data block: - processBuffer(); - // reset buffer: - bufferBits = bufferPos = 0; - } - buffer[bufferPos] = (byte) ((b << (8 - bufferRem)) & 0xff); - bufferBits += bufferRem; - // proceed to remaining data: - sourceBits -= 8; - sourcePos++; - } - // now 0 <= sourceBits <= 8; - // furthermore, all data (if any is left) is in source[sourcePos]. - if (sourceBits > 0) { - b = (source[sourcePos] << sourceGap) & 0xff; // bits are - // left-justified on b. - // process the remaining bits: - buffer[bufferPos] |= b >>> bufferRem; - } else { - b = 0; - } - if (bufferRem + sourceBits < 8) { - // all remaining data fits on buffer[bufferPos], and there still - // remains some space. - bufferBits += (int) sourceBits; - } else { - // buffer[bufferPos] is full: - bufferPos++; - bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos; - sourceBits -= 8 - bufferRem; - // now 0 <= sourceBits < 8; furthermore, all data is in - // source[sourcePos]. - if (bufferBits == 512) { - // process data block: - processBuffer(); - // reset buffer: - bufferBits = bufferPos = 0; - } - buffer[bufferPos] = (byte) ((b << (8 - bufferRem)) & 0xff); - bufferBits += (int) sourceBits; - } - } - - /** - *

- * Get the hash value from the hashing state. - *

- *

- * This method uses the invariant: bufferBits < 512 - *

- * @param digest byte[] - */ - public void NESSIEfinalize(byte[] digest) { - // append a '1'-bit: - buffer[bufferPos] |= 0x80 >>> (bufferBits & 7); - bufferPos++; // all remaining bits on the current byte are set to zero. - // pad with zero bits to complete 512N + 256 bits: - if (bufferPos > 32) { - while (bufferPos < 64) { - buffer[bufferPos++] = 0; - } - // process data block: - processBuffer(); - // reset buffer: - bufferPos = 0; - } - while (bufferPos < 32) { - buffer[bufferPos++] = 0; - } - // append bit length of hashed data: - System.arraycopy(bitLength, 0, buffer, 32, 32); - // process data block: - processBuffer(); - // return the completed message digest: - for (int i = 0, j = 0; i < 8; i++, j += 8) { - long h = hash[i]; - digest[j] = (byte) (h >>> 56); - digest[j + 1] = (byte) (h >>> 48); - digest[j + 2] = (byte) (h >>> 40); - digest[j + 3] = (byte) (h >>> 32); - digest[j + 4] = (byte) (h >>> 24); - digest[j + 5] = (byte) (h >>> 16); - digest[j + 6] = (byte) (h >>> 8); - digest[j + 7] = (byte) (h); - } - } - - /** - * Delivers string input data to the hashing algorithm. - * - * @param source plaintext data to hash (ASCII text string). - * This method maintains the invariant: bufferBits < 512 - */ - public void NESSIEadd(String source) { - if (source.length() > 0) { - byte[] data = new byte[source.length()]; - for (int i = 0; i < source.length(); i++) { - data[i] = (byte) source.charAt(i); - } - NESSIEadd(data, 8 * data.length); - } - } - - @Override - public String computeHash(String password) { - byte[] digest = new byte[DIGESTBYTES]; - NESSIEinit(); - NESSIEadd(password); - NESSIEfinalize(digest); - return display(digest); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/Wordpress.java b/src/main/java/fr/xephi/authme/security/crypts/Wordpress.java deleted file mode 100644 index f70c0949..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/Wordpress.java +++ /dev/null @@ -1,123 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.security.MessageDigestAlgorithm; -import fr.xephi.authme.security.crypts.description.HasSalt; -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.SaltType; -import fr.xephi.authme.security.crypts.description.Usage; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.SecureRandom; -import java.util.Arrays; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -@Recommendation(Usage.ACCEPTABLE) -@HasSalt(value = SaltType.TEXT, length = 9) -// Note ljacqu 20151228: Wordpress is actually a salted algorithm but salt generation is handled internally -// and isn't exposed to the outside, so we treat it as an unsalted implementation -public class Wordpress extends UnsaltedMethod { - - private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - private final SecureRandom randomGen = new SecureRandom(); - - private String encode64(byte[] src, int count) { - int i, value; - StringBuilder output = new StringBuilder(); - i = 0; - - if (src.length < count) { - byte[] t = new byte[count]; - System.arraycopy(src, 0, t, 0, src.length); - Arrays.fill(t, src.length, count - 1, (byte) 0); - src = t; - } - - do { - value = src[i] + (src[i] < 0 ? 256 : 0); - ++i; - output.append(itoa64.charAt(value & 63)); - if (i < count) { - value |= (src[i] + (src[i] < 0 ? 256 : 0)) << 8; - } - output.append(itoa64.charAt((value >> 6) & 63)); - if (i++ >= count) { - break; - } - if (i < count) { - value |= (src[i] + (src[i] < 0 ? 256 : 0)) << 16; - } - output.append(itoa64.charAt((value >> 12) & 63)); - if (i++ >= count) { - break; - } - output.append(itoa64.charAt((value >> 18) & 63)); - } while (i < count); - return output.toString(); - } - - private String crypt(String password, String setting) { - String output = "*0"; - if (((setting.length() < 2) ? setting : setting.substring(0, 2)).equalsIgnoreCase(output)) { - output = "*1"; - } - String id = (setting.length() < 3) ? setting : setting.substring(0, 3); - if (!(id.equals("$P$") || id.equals("$H$"))) { - return output; - } - int countLog2 = itoa64.indexOf(setting.charAt(3)); - if (countLog2 < 7 || countLog2 > 30) { - return output; - } - int count = 1 << countLog2; - String salt = setting.substring(4, 4 + 8); - if (salt.length() != 8) { - return output; - } - MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.MD5); - byte[] pass = stringToUtf8(password); - byte[] hash = md.digest(stringToUtf8(salt + password)); - do { - byte[] t = new byte[hash.length + pass.length]; - System.arraycopy(hash, 0, t, 0, hash.length); - System.arraycopy(pass, 0, t, hash.length, pass.length); - hash = md.digest(t); - } while (--count > 0); - output = setting.substring(0, 12); - output += encode64(hash, 16); - return output; - } - - private String gensaltPrivate(byte[] input) { - String output = "$P$"; - int iterationCountLog2 = 8; - output += itoa64.charAt(Math.min(iterationCountLog2 + 5, 30)); - output += encode64(input, 6); - return output; - } - - private byte[] stringToUtf8(String string) { - try { - return string.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new UnsupportedOperationException("This system doesn't support UTF-8!", e); - } - } - - @Override - public String computeHash(String password) { - byte random[] = new byte[6]; - randomGen.nextBytes(random); - return crypt(password, gensaltPrivate(stringToUtf8(new String(random)))); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - String hash = hashedPassword.getHash(); - String comparedHash = crypt(password, hash); - return isEqual(hash, comparedHash); - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/XAuth.java b/src/main/java/fr/xephi/authme/security/crypts/XAuth.java deleted file mode 100644 index 3cd4ceab..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/XAuth.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import fr.xephi.authme.security.crypts.description.Recommendation; -import fr.xephi.authme.security.crypts.description.Usage; - -import java.util.Locale; - -import static fr.xephi.authme.security.HashUtils.isEqual; - -@Recommendation(Usage.RECOMMENDED) -public class XAuth extends HexSaltedMethod { - - private static String getWhirlpool(String message) { - Whirlpool w = new Whirlpool(); - byte[] digest = new byte[Whirlpool.DIGESTBYTES]; - w.NESSIEinit(); - w.NESSIEadd(message); - w.NESSIEfinalize(digest); - return Whirlpool.display(digest); - } - - @Override - public String computeHash(String password, String salt, String name) { - String hash = getWhirlpool(salt + password).toLowerCase(Locale.ROOT); - int saltPos = password.length() >= hash.length() ? hash.length() - 1 : password.length(); - return hash.substring(0, saltPos) + salt + hash.substring(saltPos); - } - - @Override - public boolean comparePassword(String password, HashedPassword hashedPassword, String name) { - String hash = hashedPassword.getHash(); - int saltPos = password.length() >= hash.length() ? hash.length() - 1 : password.length(); - if (saltPos + 12 > hash.length()) { - return false; - } - String salt = hash.substring(saltPos, saltPos + 12); - return isEqual(hash, computeHash(password, salt, name)); - } - - @Override - public int getSaltLength() { - return 12; - } - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java deleted file mode 100644 index 749b5f57..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/XfBCrypt.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.security.crypts; - -import at.favre.lib.crypto.bcrypt.BCrypt; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class XfBCrypt extends BCryptBasedHash { - - public static final String SCHEME_CLASS = "XenForo_Authentication_Core12"; - private static final Pattern HASH_PATTERN = Pattern.compile("\"hash\";s.*\"(.*)?\""); - - XfBCrypt() { - super(new BCryptHasher(BCrypt.Version.VERSION_2A, 10)); - } - - /** - * Extracts the password hash from the given BLOB. - * - * @param blob the blob to process - * @return the extracted hash - */ - public static String getHashFromBlob(byte[] blob) { - String line = new String(blob); - Matcher m = HASH_PATTERN.matcher(line); - if (m.find()) { - return m.group(1); - } - return "*"; // what? - } - - public static String serializeHash(String hash) { - return "a:1:{s:4:\"hash\";s:" + hash.length() + ":\""+hash+"\";}"; - } -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java b/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java deleted file mode 100644 index bf179fff..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.xephi.authme.security.crypts.description; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Denotes a hashing algorithm that is restricted to the ASCII charset. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface AsciiRestricted { - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java b/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java deleted file mode 100644 index 0723a4dd..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.security.crypts.description; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Describes the type of salt the encryption algorithm uses. This is purely for documentation - * purposes and is ignored by the code. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface HasSalt { - - /** - * The type of the salt. - * - * @return The salt type - */ - SaltType value(); - - /** - * For text salts, the length of the salt. - * - * @return The length of the salt the algorithm uses, or 0 if not defined or not applicable. - */ - int length() default 0; - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java b/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java deleted file mode 100644 index 4b832a68..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.xephi.authme.security.crypts.description; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to mark a hash algorithm with the usage recommendation. - * - * @see Usage - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Recommendation { - - /** - * The recommendation for using the hash algorithm. - * - * @return The recommended usage - */ - Usage value(); - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java b/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java deleted file mode 100644 index 40b923fa..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.xephi.authme.security.crypts.description; - -/** - * The type of salt used by an encryption algorithm. - */ -public enum SaltType { - - /** Random, newly generated text. */ - TEXT, - - /** Salt is based on the username, including variations and repetitions thereof. */ - USERNAME, - - /** No salt. */ - NONE - -} diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java b/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java deleted file mode 100644 index 9ccc52c4..00000000 --- a/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.security.crypts.description; - -/** - * Usage recommendation that can be provided for a hash algorithm. - *

- * Use the following rules of thumb: - *

    - *
  • Hashes using MD5 may be {@link #ACCEPTABLE} but never {@link #RECOMMENDED}.
  • - *
  • Hashes using no salt or one based on the username should be {@link #DO_NOT_USE}.
  • - *
- */ -public enum Usage { - - /** The hash algorithm appears to be cryptographically secure and is one of the algorithms recommended by AuthMe. */ - RECOMMENDED, - - /** There are safer algorithms that can be chosen but using the algorithm is generally OK. */ - ACCEPTABLE, - - /** Hash algorithm is not recommended to be used. Use only if required by another system. */ - DO_NOT_USE, - - /** Algorithm that is or will be no longer supported actively. */ - DEPRECATED, - - /** The algorithm does not work properly; do not use. */ - DOES_NOT_WORK - -} diff --git a/src/main/java/fr/xephi/authme/security/totp/GenerateTotpService.java b/src/main/java/fr/xephi/authme/security/totp/GenerateTotpService.java deleted file mode 100644 index 8c689dde..00000000 --- a/src/main/java/fr/xephi/authme/security/totp/GenerateTotpService.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.xephi.authme.security.totp; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; -import fr.xephi.authme.util.expiring.ExpiringMap; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Handles the generation of new TOTP secrets for players. - */ -public class GenerateTotpService implements HasCleanup { - - private static final int NEW_TOTP_KEY_EXPIRATION_MINUTES = 5; - - private final ExpiringMap totpKeys; - - @Inject - private TotpAuthenticator totpAuthenticator; - - GenerateTotpService() { - this.totpKeys = new ExpiringMap<>(NEW_TOTP_KEY_EXPIRATION_MINUTES, TimeUnit.MINUTES); - } - - /** - * Generates a new TOTP key and returns the corresponding QR code. - * - * @param player the player to save the TOTP key for - * @return TOTP generation result - */ - public TotpGenerationResult generateTotpKey(Player player) { - TotpGenerationResult credentials = totpAuthenticator.generateTotpKey(player); - totpKeys.put(player.getName().toLowerCase(Locale.ROOT), credentials); - return credentials; - } - - /** - * Returns the generated TOTP secret of a player, if available and not yet expired. - * - * @param player the player to retrieve the TOTP key for - * @return TOTP generation result - */ - public TotpGenerationResult getGeneratedTotpKey(Player player) { - return totpKeys.get(player.getName().toLowerCase(Locale.ROOT)); - } - - public void removeGenerateTotpKey(Player player) { - totpKeys.remove(player.getName().toLowerCase(Locale.ROOT)); - } - - /** - * Returns whether the given totp code is correct for the generated TOTP key of the player. - * - * @param player the player to verify the code for - * @param totpCode the totp code to verify with the generated secret - * @return true if the input code is correct, false if the code is invalid or no unexpired totp key is available - */ - public boolean isTotpCodeCorrectForGeneratedTotpKey(Player player, String totpCode) { - TotpGenerationResult totpDetails = totpKeys.get(player.getName().toLowerCase(Locale.ROOT)); - return totpDetails != null && totpAuthenticator.checkCode(player.getName(), totpDetails.getTotpKey(), totpCode); - } - - @Override - public void performCleanup() { - totpKeys.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/security/totp/TotpAuthenticator.java b/src/main/java/fr/xephi/authme/security/totp/TotpAuthenticator.java deleted file mode 100644 index 2c787306..00000000 --- a/src/main/java/fr/xephi/authme/security/totp/TotpAuthenticator.java +++ /dev/null @@ -1,98 +0,0 @@ -package fr.xephi.authme.security.totp; - -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Table; -import com.google.common.primitives.Ints; -import com.warrenstrange.googleauth.GoogleAuthenticator; -import com.warrenstrange.googleauth.GoogleAuthenticatorKey; -import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator; -import com.warrenstrange.googleauth.IGoogleAuthenticator; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.util.Locale; - -import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE; - -/** - * Provides TOTP functions (wrapping a third-party TOTP implementation). - */ -public class TotpAuthenticator implements HasCleanup { - - private static final int CODE_RETENTION_MINUTES = 5; - - private final IGoogleAuthenticator authenticator; - private final Settings settings; - private final Table usedCodes = HashBasedTable.create(); - - @Inject - TotpAuthenticator(Settings settings) { - this.authenticator = createGoogleAuthenticator(); - this.settings = settings; - } - - /** - * @return new Google Authenticator instance - */ - protected IGoogleAuthenticator createGoogleAuthenticator() { - return new GoogleAuthenticator(); - } - - public boolean checkCode(PlayerAuth auth, String totpCode) { - return checkCode(auth.getNickname(), auth.getTotpKey(), totpCode); - } - - /** - * Returns whether the given input code matches for the provided TOTP key. - * - * @param playerName the player name - * @param totpKey the key to check with - * @param inputCode the input code to verify - * @return true if code is valid, false otherwise - */ - public boolean checkCode(String playerName, String totpKey, String inputCode) { - String nameLower = playerName.toLowerCase(Locale.ROOT); - Integer totpCode = Ints.tryParse(inputCode); - if (totpCode != null && !usedCodes.contains(nameLower, totpCode) - && authenticator.authorize(totpKey, totpCode)) { - usedCodes.put(nameLower, totpCode, System.currentTimeMillis()); - return true; - } - return false; - } - - public TotpGenerationResult generateTotpKey(Player player) { - GoogleAuthenticatorKey credentials = authenticator.createCredentials(); - String qrCodeUrl = GoogleAuthenticatorQRGenerator.getOtpAuthURL( - settings.getProperty(PluginSettings.SERVER_NAME), player.getName(), credentials); - return new TotpGenerationResult(credentials.getKey(), qrCodeUrl); - } - - @Override - public void performCleanup() { - long threshold = System.currentTimeMillis() - CODE_RETENTION_MINUTES * MILLIS_PER_MINUTE; - usedCodes.values().removeIf(value -> value < threshold); - } - - public static final class TotpGenerationResult { - private final String totpKey; - private final String authenticatorQrCodeUrl; - - public TotpGenerationResult(String totpKey, String authenticatorQrCodeUrl) { - this.totpKey = totpKey; - this.authenticatorQrCodeUrl = authenticatorQrCodeUrl; - } - - public String getTotpKey() { - return totpKey; - } - - public String getAuthenticatorQrCodeUrl() { - return authenticatorQrCodeUrl; - } - } -} diff --git a/src/main/java/fr/xephi/authme/service/AntiBotService.java b/src/main/java/fr/xephi/authme/service/AntiBotService.java deleted file mode 100644 index f902a28f..00000000 --- a/src/main/java/fr/xephi/authme/service/AntiBotService.java +++ /dev/null @@ -1,199 +0,0 @@ -package fr.xephi.authme.service; - -import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.permission.AdminPermission; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.ProtectionSettings; -import fr.xephi.authme.util.AtomicIntervalCounter; - -import javax.inject.Inject; -import java.util.Locale; -import java.util.concurrent.CopyOnWriteArrayList; - -import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE; -import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND; - -/** - * The AntiBot Service Management class. - */ -public class AntiBotService implements SettingsDependent { - - // Instances - private final Messages messages; - private final PermissionsManager permissionsManager; - private final BukkitService bukkitService; - private final CopyOnWriteArrayList antibotKicked = new CopyOnWriteArrayList<>(); - // Settings - private int duration; - // Service status - private AntiBotStatus antiBotStatus; - private boolean startup; - private MyScheduledTask disableTask; - private AtomicIntervalCounter flaggedCounter; - - @Inject - AntiBotService(Settings settings, Messages messages, PermissionsManager permissionsManager, - BukkitService bukkitService) { - // Instances - this.messages = messages; - this.permissionsManager = permissionsManager; - this.bukkitService = bukkitService; - // Initial status - disableTask = null; - antiBotStatus = AntiBotStatus.DISABLED; - startup = true; - // Load settings and start if required - reload(settings); - } - - @Override - public void reload(Settings settings) { - // Load settings - duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION); - int sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY); - int interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL); - flaggedCounter = new AtomicIntervalCounter(sensibility, interval * 1000); - - // Stop existing protection - stopProtection(); - antiBotStatus = AntiBotStatus.DISABLED; - - // If antibot is disabled, just stop - if (!settings.getProperty(ProtectionSettings.ENABLE_ANTIBOT)) { - return; - } - - // Bot activation task - Runnable enableTask = () -> antiBotStatus = AntiBotStatus.LISTENING; - - // Delay the schedule on first start - if (startup) { - int delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY); - bukkitService.scheduleSyncDelayedTask(enableTask, (long) delay * TICKS_PER_SECOND); - startup = false; - } else { - enableTask.run(); - } - } - - /** - * Transitions the anti bot service to an active status. - */ - private void startProtection() { - if (antiBotStatus == AntiBotStatus.ACTIVE) { - return; // Already activating/active - } - if (disableTask != null) { - disableTask.cancel(); - } - // Schedule auto-disable - disableTask = bukkitService.runTaskLater(this::stopProtection, (long) duration * TICKS_PER_MINUTE); - antiBotStatus = AntiBotStatus.ACTIVE; - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> { - // Inform admins - bukkitService.getOnlinePlayers().stream() - .filter(player -> permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) - .forEach(player -> messages.send(player, MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE)); - }); - } - - /** - * Transitions the anti bot service from active status back to listening. - */ - private void stopProtection() { - if (antiBotStatus != AntiBotStatus.ACTIVE) { - return; - } - - // Change status - antiBotStatus = AntiBotStatus.LISTENING; - flaggedCounter.reset(); - antibotKicked.clear(); - - // Cancel auto-disable task - disableTask.cancel(); - disableTask = null; - - // Inform admins - String durationString = Integer.toString(duration); - bukkitService.getOnlinePlayers().stream() - .filter(player -> permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) - .forEach(player -> messages.send(player, MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE, durationString)); - } - - /** - * Returns the status of the AntiBot service. - * - * @return status of the antibot service - */ - public AntiBotStatus getAntiBotStatus() { - return antiBotStatus; - } - - /** - * Allows to override the status of the protection. - * - * @param started the new protection status - */ - public void overrideAntiBotStatus(boolean started) { - if (antiBotStatus != AntiBotStatus.DISABLED) { - if (started) { - startProtection(); - } else { - stopProtection(); - } - } - } - - /** - * Returns if a player should be kicked due to antibot service. - * - * @return if the player should be kicked - */ - public boolean shouldKick() { - if (antiBotStatus == AntiBotStatus.DISABLED) { - return false; - } else if (antiBotStatus == AntiBotStatus.ACTIVE) { - return true; - } - - if (flaggedCounter.handle()) { - startProtection(); - return true; - } - return false; - } - - /** - * Returns whether the player was kicked because of activated antibot. The list is reset - * when antibot is deactivated. - * - * @param name the name to check - * - * @return true if the given name has been kicked because of Antibot - */ - public boolean wasPlayerKicked(String name) { - return antibotKicked.contains(name.toLowerCase(Locale.ROOT)); - } - - /** - * Adds a name to the list of players kicked by antibot. Should only be used when a player - * is determined to be kicked because of failed antibot verification. - * - * @param name the name to add - */ - public void addPlayerKick(String name) { - antibotKicked.addIfAbsent(name.toLowerCase(Locale.ROOT)); - } - - public enum AntiBotStatus { - LISTENING, - DISABLED, - ACTIVE - } - -} diff --git a/src/main/java/fr/xephi/authme/service/BackupService.java b/src/main/java/fr/xephi/authme/service/BackupService.java deleted file mode 100644 index 3e570c3d..00000000 --- a/src/main/java/fr/xephi/authme/service/BackupService.java +++ /dev/null @@ -1,219 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.BackupSettings; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.util.FileUtils; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Locale; - -import static fr.xephi.authme.util.Utils.logAndSendMessage; -import static fr.xephi.authme.util.Utils.logAndSendWarning; - -/** - * Performs a backup of the data source. - */ -public class BackupService { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(EmailService.class); - - private final File dataFolder; - private final File backupFolder; - private final Settings settings; - - - /** - * Constructor. - * - * @param dataFolder the data folder - * @param settings the plugin settings - */ - @Inject - public BackupService(@DataFolder File dataFolder, Settings settings) { - this.dataFolder = dataFolder; - this.backupFolder = new File(dataFolder, "backups"); - this.settings = settings; - } - - /** - * Performs a backup for the given reason. - * - * @param cause backup reason - */ - public void doBackup(BackupCause cause) { - doBackup(cause, null); - } - - /** - * Performs a backup for the given reason. - * - * @param cause backup reason - * @param sender the command sender (nullable) - */ - public void doBackup(BackupCause cause, CommandSender sender) { - if (!settings.getProperty(BackupSettings.ENABLED)) { - // Print a warning if the backup was requested via command or by another plugin - if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) { - logAndSendWarning(sender, - "Can't perform a backup: disabled in configuration. Cause of the backup: " + cause.name()); - } - return; - } else if (BackupCause.START == cause && !settings.getProperty(BackupSettings.ON_SERVER_START) - || BackupCause.STOP == cause && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) { - // Don't perform backup on start or stop if so configured - return; - } - - // Do backup and check return value! - if (doBackup()) { - logAndSendMessage(sender, - "A backup has been performed successfully. Cause of the backup: " + cause.name()); - } else { - logAndSendWarning(sender, "Error while performing a backup! Cause of the backup: " + cause.name()); - } - } - - private boolean doBackup() { - DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND); - switch (dataSourceType) { - case MYSQL: - return performMySqlBackup(); - case SQLITE: - String dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - return performFileBackup(dbName + ".db"); - case H2: - String h2dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - return performFileBackup(h2dbName + ".mv.db"); - default: - logger.warning("Unknown data source type '" + dataSourceType + "' for backup"); - } - - return false; - } - - /** - * Performs a backup for the MySQL data source. - * - * @return true if successful, false otherwise - */ - private boolean performMySqlBackup() { - FileUtils.createDirectory(backupFolder); - File sqlBackupFile = constructBackupFile("sql"); - - String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH); - boolean isUsingWindows = useWindowsCommand(backupWindowsPath); - String backupCommand = isUsingWindows - ? backupWindowsPath + "\\bin\\mysqldump.exe" + buildMysqlDumpArguments(sqlBackupFile) - : "mysqldump" + buildMysqlDumpArguments(sqlBackupFile); - - try { - Process runtimeProcess = Runtime.getRuntime().exec(backupCommand); - int processComplete = runtimeProcess.waitFor(); - if (processComplete == 0) { - logger.info("Backup created successfully. (Using Windows = " + isUsingWindows + ")"); - return true; - } else { - logger.warning("Could not create the backup! (Using Windows = " + isUsingWindows + ")"); - } - } catch (IOException | InterruptedException e) { - logger.logException("Error during backup (using Windows = " + isUsingWindows + "):", e); - } - return false; - } - - private boolean performFileBackup(String filename) { - FileUtils.createDirectory(backupFolder); - File backupFile = constructBackupFile("db"); - - try { - copy(new File(dataFolder, filename), backupFile); - return true; - } catch (IOException ex) { - logger.logException("Encountered an error during file backup:", ex); - } - return false; - } - - /** - * Check if we are under Windows and correct location of mysqldump.exe - * otherwise return error. - * - * @param windowsPath The path to check - * @return True if the path is correct, false if it is incorrect or the OS is not Windows - */ - private boolean useWindowsCommand(String windowsPath) { - String isWin = System.getProperty("os.name").toLowerCase(Locale.ROOT); - if (isWin.contains("win")) { - if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) { - return true; - } else { - logger.warning("Mysql Windows Path is incorrect. Please check it"); - return false; - } - } - return false; - } - - /** - * Builds the command line arguments to pass along when running the {@code mysqldump} command. - * - * @param sqlBackupFile the file to back up to - * @return the mysqldump command line arguments - */ - private String buildMysqlDumpArguments(File sqlBackupFile) { - String dbUsername = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); - String dbPassword = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD); - String dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); - String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); - - return " -u " + dbUsername + " -p" + dbPassword + " " + dbName - + " --tables " + tableName + " -r " + sqlBackupFile.getPath() + ".sql"; - } - - /** - * Constructs the file name to back up the data source to. - * - * @param fileExtension the file extension to use (e.g. sql) - * @return the file to back up the data to - */ - private File constructBackupFile(String fileExtension) { - String dateString = FileUtils.createCurrentTimeString(); - return new File(backupFolder, "backup" + dateString + "." + fileExtension); - } - - private static void copy(File src, File dst) throws IOException { - try (InputStream in = new FileInputStream(src); - OutputStream out = new FileOutputStream(dst)) { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - } - } - - /** - * Possible backup causes. - */ - public enum BackupCause { - START, - STOP, - COMMAND, - OTHER - } - -} diff --git a/src/main/java/fr/xephi/authme/service/BukkitService.java b/src/main/java/fr/xephi/authme/service/BukkitService.java deleted file mode 100644 index 8a899795..00000000 --- a/src/main/java/fr/xephi/authme/service/BukkitService.java +++ /dev/null @@ -1,440 +0,0 @@ -package fr.xephi.authme.service; - -import com.github.Anon8281.universalScheduler.UniversalRunnable; -import com.github.Anon8281.universalScheduler.UniversalScheduler; -import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.bukkit.BanEntry; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; - -import javax.inject.Inject; -import java.util.Collection; -import java.util.Date; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - -import static fr.xephi.authme.AuthMe.getScheduler; - -/** - * Service for operations requiring the Bukkit API, such as for scheduling. - */ -public class BukkitService implements SettingsDependent { - - /** Number of ticks per second in the Bukkit main thread. */ - public static final int TICKS_PER_SECOND = 20; - /** Number of ticks per minute. */ - public static final int TICKS_PER_MINUTE = 60 * TICKS_PER_SECOND; - /** Whether the server is running Folia. */ - private static final boolean isFolia = UniversalScheduler.isFolia; - private final AuthMe authMe; - private boolean useAsyncTasks; - - @Inject - BukkitService(AuthMe authMe, Settings settings) { - this.authMe = authMe; - reload(settings); - } - - /** - * Schedules a once off task to occur as soon as possible. - *

- * This task will be executed by the main server thread. - * - * @param task Task to be executed - */ - public void scheduleSyncDelayedTask(Runnable task) { - runTask(task); - } - - /** - * Schedules a once off task to occur after a delay. - *

- * This task will be executed by the main server thread. - * - * @param task Task to be executed - * @param delay Delay in server ticks before executing task - */ - public void scheduleSyncDelayedTask(Runnable task, long delay) { - if (isFolia) { - runTaskLater(task, delay); - } else { - Bukkit.getScheduler().runTaskLater(authMe, task, delay); // We must do this to keep compatibility - } - } - - /** - * Schedules a synchronous task if we are currently on a async thread; if not, it runs the task immediately. - * Use this when {@link #runTaskOptionallyAsync(Runnable) optionally asynchronous tasks} have to - * run something synchronously. - * - * @param task the task to be run - */ - public void scheduleSyncTaskFromOptionallyAsyncTask(Runnable task) { - if (Bukkit.isPrimaryThread()) { - runTask(task); - } else { - scheduleSyncDelayedTask(task); - } - } - - /** - * Returns a task that will run on the next server tick. - * - * @param task the task to be run - * @throws IllegalArgumentException if plugin is null - * @throws IllegalArgumentException if task is null - */ - public void runTask(Runnable task) { - if (isFolia) { - getScheduler().runTask(task); - } else { - Bukkit.getScheduler().runTask(authMe, task); - } - } - - public void runTask(Entity entity, Runnable task) { - if (isFolia) { - getScheduler().runTask(entity, task); - } else { - Bukkit.getScheduler().runTask(authMe, task); - } - } - - public void runTask(Location location, Runnable task) { - getScheduler().runTask(location, task); - } - - /** - * Runs the task synchronously if we are running Folia, else do nothing but run it. - * @param task the task to be run - */ - public void runTaskIfFolia(Runnable task) { - if (isFolia) { - runTask(task); - } else { - task.run(); - } - } - - /** - * Runs the task synchronously if we are running Folia, else do nothing but run it. - * @param task the task to be run - */ - public void runTaskIfFolia(Entity entity, Runnable task) { - if (isFolia) { - runTask(entity, task); - } else { - task.run(); - } - } - - /** - * Runs the task synchronously if we are running Folia, else do nothing but run it. - * @param task the task to be run - */ - public void runTaskIfFolia(Location location, Runnable task) { - if (isFolia) { - runTask(location, task); - } else { - task.run(); - } - } - - /** - * Returns a task that will run after the specified number of server - * ticks. - * - * @param task the task to be run - * @param delay the ticks to wait before running the task - * @return a BukkitTask that contains the id number - * @throws IllegalArgumentException if plugin is null - * @throws IllegalArgumentException if task is null - */ - public MyScheduledTask runTaskLater(Runnable task, long delay) { - return getScheduler().runTaskLater(task, delay); - } - - public MyScheduledTask runTaskLater(Entity entity, Runnable task, long delay) { - return getScheduler().runTaskLater(entity, task, delay); - } - - /** - * Schedules this task to run asynchronously or immediately executes it based on - * AuthMe's configuration. - * - * @param task the task to run - */ - public void runTaskOptionallyAsync(Runnable task) { - if (useAsyncTasks) { - runTaskAsynchronously(task); - } else { - runTask(task); - } - } - - /** - * Asynchronous tasks should never access any API in Bukkit. Great care - * should be taken to assure the thread-safety of asynchronous tasks. - *

- * Returns a task that will run asynchronously. - * - * @param task the task to be run - * @throws IllegalArgumentException if plugin is null - * @throws IllegalArgumentException if task is null - */ - public void runTaskAsynchronously(Runnable task) { - if (isFolia) { - getScheduler().runTaskAsynchronously(task); - } else { - Bukkit.getScheduler().runTaskAsynchronously(authMe, task); - } - } - - /** - * Asynchronous tasks should never access any API in Bukkit. Great care - * should be taken to assure the thread-safety of asynchronous tasks. - *

- * Returns a task that will repeatedly run asynchronously until cancelled, - * starting after the specified number of server ticks. - * - * @param task the task to be run - * @param delay the ticks to wait before running the task for the first - * time - * @param period the ticks to wait between runs - * @return a BukkitTask that contains the id number - * @throws IllegalArgumentException if task is null - * @throws IllegalStateException if this was already scheduled - */ - public MyScheduledTask runTaskTimerAsynchronously(UniversalRunnable task, long delay, long period) { - return task.runTaskTimerAsynchronously(authMe, delay, period); - } - - /** - * Schedules the given task to repeatedly run until cancelled, starting after the - * specified number of server ticks. - * - * @param task the task to schedule - * @param delay the ticks to wait before running the task - * @param period the ticks to wait between runs - * @return a BukkitTask that contains the id number - * @throws IllegalArgumentException if plugin is null - * @throws IllegalStateException if this was already scheduled - */ - public MyScheduledTask runTaskTimer(UniversalRunnable task, long delay, long period) { - return task.runTaskTimer(authMe, delay, period); - } - - /** - * Broadcast a message to all players. - * - * @param message the message - * @return the number of players - */ - public int broadcastMessage(String message) { - return Bukkit.broadcastMessage(message); - } - - /** - * Gets the player with the exact given name, case insensitive. - * - * @param name Exact name of the player to retrieve - * @return a player object if one was found, null otherwise - */ - public Player getPlayerExact(String name) { - return authMe.getServer().getPlayerExact(name); - } - - /** - * Gets the player by the given name, regardless if they are offline or - * online. - *

- * This method may involve a blocking web request to get the UUID for the - * given name. - *

- * This will return an object even if the player does not exist. To this - * method, all players will exist. - * - * @param name the name the player to retrieve - * @return an offline player - */ - public OfflinePlayer getOfflinePlayer(String name) { - return authMe.getServer().getOfflinePlayer(name); - } - - /** - * Gets a set containing all banned players. - * - * @return a set containing banned players - */ - public Set getBannedPlayers() { - return Bukkit.getBannedPlayers(); - } - - /** - * Gets every player that has ever played on this server. - * - * @return an array containing all previous players - */ - public OfflinePlayer[] getOfflinePlayers() { - return Bukkit.getOfflinePlayers(); - } - - /** - * Gets a view of all currently online players. - * - * @return collection of online players - */ - @SuppressWarnings("unchecked") - public Collection getOnlinePlayers() { - return (Collection) Bukkit.getOnlinePlayers(); - } - - /** - * Calls an event with the given details. - * - * @param event Event details - * @throws IllegalStateException Thrown when an asynchronous event is - * fired from synchronous code. - */ - public void callEvent(Event event) { - Bukkit.getPluginManager().callEvent(event); - } - - /** - * Creates an event with the provided function and emits it. - * - * @param eventSupplier the event supplier: function taking a boolean specifying whether AuthMe is configured - * in async mode or not - * @param the event type - * @return the event that was created and emitted - */ - public E createAndCallEvent(Function eventSupplier) { - E event = eventSupplier.apply(useAsyncTasks); - callEvent(event); - return event; - } - - /** - * Creates a PotionEffect with blindness for the given duration in ticks. - * - * @param timeoutInTicks duration of the effect in ticks - * @return blindness potion effect - */ - public PotionEffect createBlindnessEffect(int timeoutInTicks) { - return new PotionEffect(PotionEffectType.BLINDNESS, timeoutInTicks, 2); - } - - /** - * Gets the world with the given name. - * - * @param name the name of the world to retrieve - * @return a world with the given name, or null if none exists - */ - public World getWorld(String name) { - return Bukkit.getWorld(name); - } - - /** - * Dispatches a command on this server, and executes it if found. - * - * @param sender the apparent sender of the command - * @param commandLine the command + arguments. Example: test abc 123 - * @return returns false if no target is found - */ - public boolean dispatchCommand(CommandSender sender, String commandLine) { - return Bukkit.dispatchCommand(sender, commandLine); - } - - /** - * Dispatches a command to be run as console user on this server, and executes it if found. - * - * @param commandLine the command + arguments. Example: test abc 123 - * @return returns false if no target is found - */ - public boolean dispatchConsoleCommand(String commandLine) { - return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), commandLine); - } - - @Override - public void reload(Settings settings) { - useAsyncTasks = settings.getProperty(PluginSettings.USE_ASYNC_TASKS); - } - - /** - * Send the specified bytes to bungeecord using the specified player connection. - * - * @param player the player - * @param bytes the message - */ - public void sendBungeeMessage(Player player, byte[] bytes) { - player.sendPluginMessage(authMe, "BungeeCord", bytes); - } - - /** - * Send the specified bytes to bungeecord using the specified player connection. - * - * @param player the player - * @param bytes the message - */ - public void sendVelocityMessage(Player player, byte[] bytes) { - if (player != null) { - player.sendPluginMessage(authMe, "authmevelocity:main", bytes); - } else { - Bukkit.getServer().sendPluginMessage(authMe, "authmevelocity:main", bytes); - } - } - - - /** - * Adds a ban to the list. If a previous ban exists, this will - * update the previous entry. - * - * @param ip the ip of the ban - * @param reason reason for the ban, null indicates implementation default - * @param expires date for the ban's expiration (unban), or null to imply - * forever - * @param source source of the ban, null indicates implementation default - * @return the entry for the newly created ban, or the entry for the - * (updated) previous ban - */ - public BanEntry banIp(String ip, String reason, Date expires, String source) { - return Bukkit.getServer().getBanList(BanList.Type.IP).addBan(ip, reason, expires, source); - } - - /** - * Returns an optional with a boolean indicating whether bungeecord is enabled or not if the - * server implementation is Spigot. Otherwise returns an empty optional. - * - * @return Optional with configuration value for Spigot, empty optional otherwise - */ - public Optional isBungeeCordConfiguredForSpigot() { - try { - YamlConfiguration spigotConfig = Bukkit.spigot().getConfig(); - return Optional.of(spigotConfig.getBoolean("settings.bungeecord")); - } catch (NoSuchMethodError e) { - return Optional.empty(); - } - } - - /** - * @return the IP string that this server is bound to, otherwise empty string - */ - public String getIp() { - return Bukkit.getServer().getIp(); - } -} diff --git a/src/main/java/fr/xephi/authme/service/CommonService.java b/src/main/java/fr/xephi/authme/service/CommonService.java deleted file mode 100644 index 92a49267..00000000 --- a/src/main/java/fr/xephi/authme/service/CommonService.java +++ /dev/null @@ -1,84 +0,0 @@ -package fr.xephi.authme.service; - -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.permission.PermissionNode; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -/** - * Service for the most common operations regarding settings, messages and permissions. - */ -public class CommonService { - - @Inject - private Settings settings; - - @Inject - private Messages messages; - - @Inject - private PermissionsManager permissionsManager; - - CommonService() { - } - - /** - * Retrieves a property's value. - * - * @param property the property to retrieve - * @param the property type - * @return the property's value - */ - public T getProperty(Property property) { - return settings.getProperty(property); - } - - /** - * Sends a message to the command sender. - * - * @param sender the command sender - * @param key the message key - */ - public void send(CommandSender sender, MessageKey key) { - messages.send(sender, key); - } - - /** - * Sends a message to the command sender with the given replacements. - * - * @param sender the command sender - * @param key the message key - * @param replacements the replacements to apply to the message - */ - public void send(CommandSender sender, MessageKey key, String... replacements) { - messages.send(sender, key, replacements); - } - - /** - * Retrieves a message in one piece. - * - * @param sender The entity to send the message to - * @param key the key of the message - * @return the message - */ - public String retrieveSingleMessage(CommandSender sender, MessageKey key) { - return messages.retrieveSingle(sender, key); - } - - /** - * Checks whether the player has the given permission. - * - * @param player the player - * @param node the permission node to check - * @return true if player has permission, false otherwise - */ - public boolean hasPermission(Player player, PermissionNode node) { - return permissionsManager.hasPermission(player, node); - } -} diff --git a/src/main/java/fr/xephi/authme/service/GeoIpService.java b/src/main/java/fr/xephi/authme/service/GeoIpService.java deleted file mode 100644 index bf7252ff..00000000 --- a/src/main/java/fr/xephi/authme/service/GeoIpService.java +++ /dev/null @@ -1,188 +0,0 @@ -package fr.xephi.authme.service; - -import com.google.common.annotations.VisibleForTesting; -import com.maxmind.db.GeoIp2Provider; -import com.maxmind.db.Reader; -import com.maxmind.db.Reader.FileMode; -import com.maxmind.db.cache.CHMCache; -import com.maxmind.db.model.Country; -import com.maxmind.db.model.CountryResponse; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.util.InternetProtocolUtils; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Optional; - -public class GeoIpService { - - //private static final String LICENSE = - //"[LICENSE] This product includes GeoLite2 data created by MaxMind, available at https://www.maxmind.com"; - - private static final String DATABASE_NAME = "GeoLite2-Country"; - private static final String DATABASE_FILE = DATABASE_NAME + ".mmdb"; - - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(GeoIpService.class); - private final Path dataFile; - - private GeoIp2Provider databaseReader; - private volatile boolean downloading; - - @Inject - GeoIpService(@DataFolder File dataFolder){ - this.dataFile = dataFolder.toPath().resolve(DATABASE_FILE); - - // Fires download of recent data or the initialization of the look up service - isDataAvailable(); - } - - @VisibleForTesting - GeoIpService(@DataFolder File dataFolder, GeoIp2Provider reader) { - this.dataFile = dataFolder.toPath().resolve(DATABASE_FILE); - - this.databaseReader = reader; - } - - /** - * Download (if absent or old) the GeoIpLite data file and then try to load it. - * - * @return True if the data is available, false otherwise. - */ - private synchronized boolean isDataAvailable() { - if (downloading) { - // we are currently downloading the database - return false; - } - - if (databaseReader != null) { - // everything is initialized - return true; - } - - if (Files.exists(dataFile)) { - try { - startReading(); - return true; - } catch (IOException ioEx) { - logger.logException("Failed to load GeoLiteAPI database", ioEx); - return false; - } - } - - // File is outdated or doesn't exist - let's try to download the data file! - // use bukkit's cached threads - return false; - } - - /** - * - */ - - private void startReading() throws IOException { - databaseReader = new Reader(dataFile.toFile(), FileMode.MEMORY, new CHMCache()); - - // clear downloading flag, because we now have working reader instance - downloading = false; - } - - /** - * Downloads the archive to the destination file if it's newer than the locally version. - * - * @param lastModified modification timestamp of the already present file - * @param destination save file - * @return null if no updates were found, the MD5 hash of the downloaded archive if successful - * @throws IOException if failed during downloading and writing to destination file - */ - - /** - * Downloads the archive to the destination file if it's newer than the locally version. - * - * @param destination save file - * @return null if no updates were found, the MD5 hash of the downloaded archive if successful - * @throws IOException if failed during downloading and writing to destination file - */ - - /** - * Verify if the expected checksum is equal to the checksum of the given file. - * - * @param function the checksum function like MD5, SHA256 used to generate the checksum from the file - * @param file the file we want to calculate the checksum from - * @param expectedChecksum the expected checksum - * @throws IOException on I/O error reading the file or the checksum verification failed - */ - - /** - * Extract the database from gzipped data. Existing outputFile will be replaced if it already exists. - * - * @param inputFile gzipped database input file - * @param outputFile destination file for the database - * @throws IOException on I/O error reading the archive, or writing the output - */ - - /** - * Get the country code of the given IP address. - * - * @param ip textual IP address to lookup. - * @return two-character ISO 3166-1 alpha code for the country, "LOCALHOST" for local addresses - * or "--" if it cannot be fetched. - */ - public String getCountryCode(String ip) { - if (InternetProtocolUtils.isLocalAddress(ip)) { - return "LOCALHOST"; - } - return getCountry(ip).map(Country::getIsoCode).orElse("--"); - } - - /** - * Get the country name of the given IP address. - * - * @param ip textual IP address to lookup. - * @return The name of the country, "LocalHost" for local addresses, or "N/A" if it cannot be fetched. - */ - public String getCountryName(String ip) { - if (InternetProtocolUtils.isLocalAddress(ip)) { - return "LocalHost"; - } - return getCountry(ip).map(Country::getName).orElse("N/A"); - } - - /** - * Get the country of the given IP address - * - * @param ip textual IP address to lookup - * @return the wrapped Country model or {@link Optional#empty()} if - *

    - *
  • Database reader isn't initialized
  • - *
  • MaxMind has no record about this IP address
  • - *
  • IP address is local
  • - *
  • Textual representation is not a valid IP address
  • - *
- */ - private Optional getCountry(String ip) { - if (ip == null || ip.isEmpty() || !isDataAvailable()) { - return Optional.empty(); - } - - try { - InetAddress address = InetAddress.getByName(ip); - - // Reader.getCountry() can be null for unknown addresses - return Optional.ofNullable(databaseReader.getCountry(address)).map(CountryResponse::getCountry); - } catch (UnknownHostException e) { - // Ignore invalid ip addresses - // Legacy GEO IP Database returned a unknown country object with Country-Code: '--' and Country-Name: 'N/A' - } catch (IOException ioEx) { - logger.logException("Cannot lookup country for " + ip + " at GEO IP database", ioEx); - } - - return Optional.empty(); - } -} diff --git a/src/main/java/fr/xephi/authme/service/HelpTranslationGenerator.java b/src/main/java/fr/xephi/authme/service/HelpTranslationGenerator.java deleted file mode 100644 index e1c8c5ba..00000000 --- a/src/main/java/fr/xephi/authme/service/HelpTranslationGenerator.java +++ /dev/null @@ -1,126 +0,0 @@ -package fr.xephi.authme.service; - -import com.google.common.collect.ImmutableMap; -import fr.xephi.authme.command.CommandArgumentDescription; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.CommandInitializer; -import fr.xephi.authme.command.help.HelpMessage; -import fr.xephi.authme.command.help.HelpMessagesService; -import fr.xephi.authme.command.help.HelpSection; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.message.MessagePathHelper; -import fr.xephi.authme.permission.DefaultPermission; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * Generates the full command structure for the help translation and saves it to the current help file, - * preserving already existing entries. - */ -public class HelpTranslationGenerator { - - @Inject - private CommandInitializer commandInitializer; - - @Inject - private HelpMessagesService helpMessagesService; - - @Inject - private Settings settings; - - @DataFolder - @Inject - private File dataFolder; - - /** - * Updates the help file to contain entries for all commands. - * - * @return the help file that has been updated - * @throws IOException if the help file cannot be written to - */ - public File updateHelpFile() throws IOException { - String languageCode = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); - File helpFile = new File(dataFolder, MessagePathHelper.createHelpMessageFilePath(languageCode)); - Map helpEntries = generateHelpMessageEntries(); - - String helpEntriesYaml = exportToYaml(helpEntries); - Files.write(helpFile.toPath(), helpEntriesYaml.getBytes(), StandardOpenOption.TRUNCATE_EXISTING); - return helpFile; - } - - private static String exportToYaml(Map helpEntries) { - DumperOptions options = new DumperOptions(); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - options.setAllowUnicode(true); - return new Yaml(options).dump(helpEntries); - } - - /** - * Generates entries for a complete help text file. - * - * @return help text entries to save - */ - private Map generateHelpMessageEntries() { - Map messageEntries = new LinkedHashMap<>(HelpMessage.values().length); - for (HelpMessage message : HelpMessage.values()) { - messageEntries.put(message.getEntryKey(), helpMessagesService.getMessage(message)); - } - - Map defaultPermissions = new LinkedHashMap<>(); - for (DefaultPermission defaultPermission : DefaultPermission.values()) { - defaultPermissions.put(HelpMessagesService.getDefaultPermissionsSubPath(defaultPermission), - helpMessagesService.getMessage(defaultPermission)); - } - messageEntries.put("defaultPermissions", defaultPermissions); - - Map sectionEntries = new LinkedHashMap<>(HelpSection.values().length); - for (HelpSection section : HelpSection.values()) { - sectionEntries.put(section.getEntryKey(), helpMessagesService.getMessage(section)); - } - - Map commandEntries = new LinkedHashMap<>(); - for (CommandDescription command : commandInitializer.getCommands()) { - generateCommandEntries(command, commandEntries); - } - - return ImmutableMap.of( - "common", messageEntries, - "section", sectionEntries, - "commands", commandEntries); - } - - /** - * Adds YAML entries for the provided command its children to the given map. - * - * @param command the command to process (including its children) - * @param commandEntries the map to add the generated entries to - */ - private void generateCommandEntries(CommandDescription command, Map commandEntries) { - CommandDescription translatedCommand = helpMessagesService.buildLocalizedDescription(command); - Map commandData = new LinkedHashMap<>(); - commandData.put("description", translatedCommand.getDescription()); - commandData.put("detailedDescription", translatedCommand.getDetailedDescription()); - - int i = 1; - for (CommandArgumentDescription argument : translatedCommand.getArguments()) { - Map argumentData = new LinkedHashMap<>(2); - argumentData.put("label", argument.getName()); - argumentData.put("description", argument.getDescription()); - commandData.put("arg" + i, argumentData); - ++i; - } - - commandEntries.put(HelpMessagesService.getCommandSubPath(translatedCommand), commandData); - translatedCommand.getChildren().forEach(child -> generateCommandEntries(child, commandEntries)); - } -} diff --git a/src/main/java/fr/xephi/authme/service/JoinMessageService.java b/src/main/java/fr/xephi/authme/service/JoinMessageService.java deleted file mode 100644 index d4c5b4c6..00000000 --- a/src/main/java/fr/xephi/authme/service/JoinMessageService.java +++ /dev/null @@ -1,45 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.util.StringUtils; - -import javax.inject.Inject; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * The JoinMessageService class. - */ -public class JoinMessageService { - - private BukkitService bukkitService; - - private Map joinMessages; - - @Inject - JoinMessageService(BukkitService bukkitService) { - this.bukkitService = bukkitService; - joinMessages = new ConcurrentHashMap<>(); - } - - /** - * Store a join message. - * - * @param playerName the player name - * @param string the join message - */ - public void putMessage(String playerName, String string) { - joinMessages.put(playerName, string); - } - - /** - * Broadcast the join message of the specified player. - * - * @param playerName the player name - */ - public void sendMessage(String playerName) { - String joinMessage = joinMessages.remove(playerName); - if (!StringUtils.isBlank(joinMessage)) { - bukkitService.broadcastMessage(joinMessage); - } - } -} diff --git a/src/main/java/fr/xephi/authme/service/MigrationService.java b/src/main/java/fr/xephi/authme/service/MigrationService.java deleted file mode 100644 index de8d88a7..00000000 --- a/src/main/java/fr/xephi/authme/service/MigrationService.java +++ /dev/null @@ -1,54 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.security.crypts.Sha256; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; - -import java.util.List; - -/** - * Migrations to perform during the initialization of AuthMe. - */ -public final class MigrationService { - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(MigrationService.class); - - private MigrationService() { - } - - /** - * Hash all passwords to Sha256 and updated the setting if the password hash is set to the deprecated PLAINTEXT. - * - * @param settings The settings instance - * @param dataSource The data source - * @param authmeSha256 Instance to the AuthMe Sha256 encryption method implementation - */ - public static void changePlainTextToSha256(Settings settings, DataSource dataSource, - Sha256 authmeSha256) { - if (HashAlgorithm.PLAINTEXT == settings.getProperty(SecuritySettings.PASSWORD_HASH)) { - logger.warning("Your HashAlgorithm has been detected as plaintext and is now deprecated;" - + " it will be changed and hashed now to the AuthMe default hashing method"); - logger.warning("Don't stop your server; wait for the conversion to have been completed!"); - List allAuths = dataSource.getAllAuths(); - for (PlayerAuth auth : allAuths) { - String hash = auth.getPassword().getHash(); - if (hash.startsWith("$SHA$")) { - logger.warning("Skipping conversion for " + auth.getNickname() + "; detected SHA hash"); - } else { - HashedPassword hashedPassword = authmeSha256.computeHash(hash, auth.getNickname()); - auth.setPassword(hashedPassword); - dataSource.updatePassword(auth); - } - } - settings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); - settings.save(); - logger.info("Migrated " + allAuths.size() + " accounts from plaintext to SHA256"); - } - } -} diff --git a/src/main/java/fr/xephi/authme/service/PasswordRecoveryService.java b/src/main/java/fr/xephi/authme/service/PasswordRecoveryService.java deleted file mode 100644 index 01f96300..00000000 --- a/src/main/java/fr/xephi/authme/service/PasswordRecoveryService.java +++ /dev/null @@ -1,187 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.mail.EmailService; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.message.Messages; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.RandomStringUtils; -import fr.xephi.authme.util.expiring.Duration; -import fr.xephi.authme.util.expiring.ExpiringMap; -import fr.xephi.authme.util.expiring.ExpiringSet; -import org.bukkit.entity.Player; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH; - -/** - * Manager for password recovery. - */ -public class PasswordRecoveryService implements Reloadable, HasCleanup { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PasswordRecoveryService.class); - - @Inject - private CommonService commonService; - - @Inject - private DataSource dataSource; - - @Inject - private EmailService emailService; - - @Inject - private PasswordSecurity passwordSecurity; - - @Inject - private RecoveryCodeService recoveryCodeService; - - @Inject - private Messages messages; - - private ExpiringSet emailCooldown; - private ExpiringMap successfulRecovers; - - @PostConstruct - private void initEmailCooldownSet() { - emailCooldown = new ExpiringSet<>( - commonService.getProperty(SecuritySettings.EMAIL_RECOVERY_COOLDOWN_SECONDS), TimeUnit.SECONDS); - successfulRecovers = new ExpiringMap<>( - commonService.getProperty(SecuritySettings.PASSWORD_CHANGE_TIMEOUT), TimeUnit.MINUTES); - } - - /** - * Create a new recovery code and send it to the player - * via email. - * - * @param player The player getting the code. - * @param email The email to send the code to. - */ - public void createAndSendRecoveryCode(Player player, String email) { - if (!checkEmailCooldown(player)) { - return; - } - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'年'MM'月'dd'日' HH:mm:ss"); - Date date = new Date(System.currentTimeMillis()); - String recoveryCode = recoveryCodeService.generateCode(player.getName()); - boolean couldSendMail = emailService.sendRecoveryCode(player.getName(), email, recoveryCode, dateFormat.format(date)); - if (couldSendMail) { - commonService.send(player, MessageKey.RECOVERY_CODE_SENT); - emailCooldown.add(player.getName().toLowerCase(Locale.ROOT)); - } else { - commonService.send(player, MessageKey.EMAIL_SEND_FAILURE); - } - } - - /** - * Generate a new password and send it to the player via - * email. This will update the database with the new password. - * - * @param player The player recovering their password. - * @param email The email to send the password to. - */ - public void generateAndSendNewPassword(Player player, String email) { - if (!checkEmailCooldown(player)) { - return; - } - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'年'MM'月'dd'日' HH:mm:ss"); - Date date = new Date(System.currentTimeMillis()); - - String name = player.getName(); - String thePass = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH)); - HashedPassword hashNew = passwordSecurity.computeHash(thePass, name); - - logger.info("Generating new password for '" + name + "'"); - - dataSource.updatePassword(name, hashNew); - boolean couldSendMail = emailService.sendPasswordMail(name, email, thePass, dateFormat.format(date)); - if (couldSendMail) { - commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); - emailCooldown.add(player.getName().toLowerCase(Locale.ROOT)); - } else { - commonService.send(player, MessageKey.EMAIL_SEND_FAILURE); - } - } - - /** - * Allows a player to change their password after - * correctly entering a recovery code. - * - * @param player The player recovering their password. - */ - public void addSuccessfulRecovery(Player player) { - String name = player.getName(); - String address = PlayerUtils.getPlayerIp(player); - - successfulRecovers.put(name, address); - commonService.send(player, MessageKey.RECOVERY_CHANGE_PASSWORD); - } - - /** - * Removes a player from the list of successful recovers so that he can - * no longer use the /email setpassword command. - * - * @param player The player to remove. - */ - public void removeFromSuccessfulRecovery(Player player) { - successfulRecovers.remove(player.getName()); - } - - /** - * Check if a player is able to have emails sent. - * - * @param player The player to check. - * @return True if the player is not on cooldown. - */ - private boolean checkEmailCooldown(Player player) { - Duration waitDuration = emailCooldown.getExpiration(player.getName().toLowerCase(Locale.ROOT)); - if (waitDuration.getDuration() > 0) { - String durationText = messages.formatDuration(waitDuration); - messages.send(player, MessageKey.EMAIL_COOLDOWN_ERROR, durationText); - return false; - } - return true; - } - - /** - * Checks if a player can change their password after recovery - * using the /email setpassword command. - * - * @param player The player to check. - * @return True if the player can change their password. - */ - public boolean canChangePassword(Player player) { - String name = player.getName(); - String playerAddress = PlayerUtils.getPlayerIp(player); - String storedAddress = successfulRecovers.get(name); - - return storedAddress != null && playerAddress.equals(storedAddress); - } - - @Override - public void reload() { - emailCooldown.setExpiration( - commonService.getProperty(SecuritySettings.EMAIL_RECOVERY_COOLDOWN_SECONDS), TimeUnit.SECONDS); - successfulRecovers.setExpiration( - commonService.getProperty(SecuritySettings.PASSWORD_CHANGE_TIMEOUT), TimeUnit.MINUTES); - } - - @Override - public void performCleanup() { - emailCooldown.removeExpiredEntries(); - successfulRecovers.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/service/PluginHookService.java b/src/main/java/fr/xephi/authme/service/PluginHookService.java deleted file mode 100644 index 3615aa73..00000000 --- a/src/main/java/fr/xephi/authme/service/PluginHookService.java +++ /dev/null @@ -1,197 +0,0 @@ -package fr.xephi.authme.service; - -import ch.jalu.injector.annotations.NoFieldScan; -import com.earth2me.essentials.Essentials; -import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.api.MVWorldManager; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; - -import javax.inject.Inject; -import java.io.File; - -/** - * Hooks into third-party plugins and allows to perform actions on them. - */ -@NoFieldScan -public class PluginHookService { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PluginHookService.class); - private final PluginManager pluginManager; - private Essentials essentials; - private Plugin cmi; - private MultiverseCore multiverse; - - /** - * Constructor. - * - * @param pluginManager The server's plugin manager - */ - @Inject - public PluginHookService(PluginManager pluginManager) { - this.pluginManager = pluginManager; - tryHookToEssentials(); - tryHookToCmi(); - tryHookToMultiverse(); - } - - /** - * Enable or disable the social spy status of the given user if Essentials is available. - * - * @param player The player to modify - * @param socialSpyStatus The social spy status (enabled/disabled) to set - */ - public void setEssentialsSocialSpyStatus(Player player, boolean socialSpyStatus) { - if (essentials != null) { - essentials.getUser(player).setSocialSpyEnabled(socialSpyStatus); - } - } - - /** - * If Essentials is hooked into, return Essentials' data folder. - * - * @return The Essentials data folder, or null if unavailable - */ - public File getEssentialsDataFolder() { - if (essentials != null) { - return essentials.getDataFolder(); - } - return null; - } - - /** - * If CMI is hooked into, return CMI' data folder. - * - * @return The CMI data folder, or null if unavailable - */ - public File getCmiDataFolder() { - Plugin plugin = pluginManager.getPlugin("CMI"); - if (plugin == null) { - return null; - } - return plugin.getDataFolder(); - } - - /** - * Return the spawn of the given world as defined by Multiverse (if available). - * - * @param world The world to get the Multiverse spawn for - * @return The spawn location from Multiverse, or null if unavailable - */ - public Location getMultiverseSpawn(World world) { - if (multiverse != null) { - MVWorldManager manager = multiverse.getMVWorldManager(); - if (manager.isMVWorld(world)) { - return manager.getMVWorld(world).getSpawnLocation(); - } - } - return null; - } - - // ------ - // "Is plugin available" methods - // ------ - - /** - * @return true if we have a hook to Essentials, false otherwise - */ - public boolean isEssentialsAvailable() { - return essentials != null; - } - - /** - * @return true if we have a hook to CMI, false otherwise - */ - public boolean isCmiAvailable() { - return cmi != null; - } - - /** - * @return true if we have a hook to Multiverse, false otherwise - */ - public boolean isMultiverseAvailable() { - return multiverse != null; - } - - // ------ - // Hook methods - // ------ - - /** - * Attempts to create a hook into Essentials. - */ - public void tryHookToEssentials() { - try { - essentials = getPlugin(pluginManager, "Essentials", Essentials.class); - } catch (Exception | NoClassDefFoundError ignored) { - essentials = null; - } - } - - /** - * Attempts to create a hook into CMI. - */ - public void tryHookToCmi() { - try { - cmi = getPlugin(pluginManager, "CMI", Plugin.class); - } catch (Exception | NoClassDefFoundError ignored) { - cmi = null; - } - } - - /** - * Attempts to create a hook into Multiverse. - */ - public void tryHookToMultiverse() { - try { - multiverse = getPlugin(pluginManager, "Multiverse-Core", MultiverseCore.class); - } catch (Exception | NoClassDefFoundError ignored) { - multiverse = null; - } - } - - // ------ - // Unhook methods - // ------ - - /** - * Unhooks from Essentials. - */ - public void unhookEssentials() { - essentials = null; - } - - /** - * Unhooks from CMI. - */ - public void unhookCmi() { - cmi = null; - } - - /** - * Unhooks from Multiverse. - */ - public void unhookMultiverse() { - multiverse = null; - } - - // ------ - // Helpers - // ------ - - private T getPlugin(PluginManager pluginManager, String name, Class clazz) - throws Exception, NoClassDefFoundError { - if (pluginManager.isPluginEnabled(name)) { - T plugin = clazz.cast(pluginManager.getPlugin(name)); - logger.info("Hooked successfully into " + name); - return plugin; - } - return null; - } - -} diff --git a/src/main/java/fr/xephi/authme/service/RecoveryCodeService.java b/src/main/java/fr/xephi/authme/service/RecoveryCodeService.java deleted file mode 100644 index dcccb36d..00000000 --- a/src/main/java/fr/xephi/authme/service/RecoveryCodeService.java +++ /dev/null @@ -1,111 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.RandomStringUtils; -import fr.xephi.authme.util.expiring.ExpiringMap; -import fr.xephi.authme.util.expiring.TimedCounter; - -import javax.inject.Inject; -import java.util.concurrent.TimeUnit; - -/** - * Manager for recovery codes. - */ -public class RecoveryCodeService implements SettingsDependent, HasCleanup { - - private final ExpiringMap recoveryCodes; - private final TimedCounter playerTries; - private int recoveryCodeLength; - private int recoveryCodeExpiration; - private int recoveryCodeMaxTries; - - @Inject - RecoveryCodeService(Settings settings) { - recoveryCodeLength = settings.getProperty(SecuritySettings.RECOVERY_CODE_LENGTH); - recoveryCodeExpiration = settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID); - recoveryCodeMaxTries = settings.getProperty(SecuritySettings.RECOVERY_CODE_MAX_TRIES); - recoveryCodes = new ExpiringMap<>(recoveryCodeExpiration, TimeUnit.HOURS); - playerTries = new TimedCounter<>(recoveryCodeExpiration, TimeUnit.HOURS); - } - - /** - * @return whether recovery codes are enabled or not - */ - public boolean isRecoveryCodeNeeded() { - return recoveryCodeLength > 0 && recoveryCodeExpiration > 0; - } - - /** - * Generates the recovery code for the given player. - * - * @param player the player to generate a code for - * @return the generated code - */ - public String generateCode(String player) { - String code = RandomStringUtils.generateHex(recoveryCodeLength); - - playerTries.put(player, recoveryCodeMaxTries); - recoveryCodes.put(player, code); - return code; - } - - /** - * Checks whether the supplied code is valid for the given player. - * - * @param player the player to check for - * @param code the code to check - * @return true if the code matches and has not expired, false otherwise - */ - public boolean isCodeValid(String player, String code) { - String storedCode = recoveryCodes.get(player); - playerTries.decrement(player); - return storedCode != null && storedCode.equals(code); - } - - /** - * Checks whether a player has tries remaining to enter a code. - * - * @param player The player to check for. - * @return True if the player has tries left. - */ - public boolean hasTriesLeft(String player) { - return playerTries.get(player) > 0; - } - - /** - * Get the number of attempts a player has to enter a code. - * - * @param player The player to check for. - * @return The number of tries left. - */ - public int getTriesLeft(String player) { - return playerTries.get(player); - } - - /** - * Removes the player's recovery code if present. - * - * @param player the player - */ - public void removeCode(String player) { - recoveryCodes.remove(player); - playerTries.remove(player); - } - - @Override - public void reload(Settings settings) { - recoveryCodeLength = settings.getProperty(SecuritySettings.RECOVERY_CODE_LENGTH); - recoveryCodeExpiration = settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID); - recoveryCodeMaxTries = settings.getProperty(SecuritySettings.RECOVERY_CODE_MAX_TRIES); - recoveryCodes.setExpiration(recoveryCodeExpiration, TimeUnit.HOURS); - } - - @Override - public void performCleanup() { - recoveryCodes.removeExpiredEntries(); - playerTries.removeExpiredEntries(); - } -} diff --git a/src/main/java/fr/xephi/authme/service/SessionService.java b/src/main/java/fr/xephi/authme/service/SessionService.java deleted file mode 100644 index b4092b45..00000000 --- a/src/main/java/fr/xephi/authme/service/SessionService.java +++ /dev/null @@ -1,105 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.RestoreSessionEvent; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.PlayerUtils; -import org.bukkit.entity.Player; - -import javax.inject.Inject; - -import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE; - -/** - * Handles the user sessions. - */ -public class SessionService implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(SessionService.class); - private final CommonService service; - private final BukkitService bukkitService; - private final DataSource database; - - private boolean isEnabled; - - @Inject - SessionService(CommonService service, BukkitService bukkitService, DataSource database) { - this.service = service; - this.bukkitService = bukkitService; - this.database = database; - reload(); - } - - /** - * Returns whether the player has a session he can resume. - * - * @param player the player to check - * @return true if there is a current session, false otherwise - */ - public boolean canResumeSession(Player player) { - final String name = player.getName(); - if (isEnabled && database.hasSession(name)) { - database.setUnlogged(name); - database.revokeSession(name); - PlayerAuth auth = database.getAuth(name); - - SessionState state = fetchSessionStatus(auth, player); - if (state.equals(SessionState.VALID)) { - RestoreSessionEvent event = bukkitService.createAndCallEvent( - isAsync -> new RestoreSessionEvent(player, isAsync)); - return !event.isCancelled(); - } else if (state.equals(SessionState.IP_CHANGED)) { - service.send(player, MessageKey.SESSION_EXPIRED); - } - } - return false; - } - - /** - * Checks if the given Player has a current session by comparing its properties - * with the given PlayerAuth's. - * - * @param auth the player auth - * @param player the associated player - * @return SessionState based on the state of the session (VALID, NOT_VALID, OUTDATED, IP_CHANGED) - */ - private SessionState fetchSessionStatus(PlayerAuth auth, Player player) { - if (auth == null) { - logger.warning("No PlayerAuth in database for '" + player.getName() + "' during session check"); - return SessionState.NOT_VALID; - } else if (auth.getLastLogin() == null) { - return SessionState.NOT_VALID; - } - long timeSinceLastLogin = System.currentTimeMillis() - auth.getLastLogin(); - - if (timeSinceLastLogin > 0 - && timeSinceLastLogin < service.getProperty(PluginSettings.SESSIONS_TIMEOUT) * MILLIS_PER_MINUTE) { - if (PlayerUtils.getPlayerIp(player).equals(auth.getLastIp())) { - return SessionState.VALID; - } else { - return SessionState.IP_CHANGED; - } - } - return SessionState.OUTDATED; - } - - public void grantSession(String name) { - if (isEnabled) { - database.grantSession(name); - } - } - - public void revokeSession(String name) { - database.revokeSession(name); - } - - @Override - public void reload() { - this.isEnabled = service.getProperty(PluginSettings.SESSIONS_ENABLED); - } -} diff --git a/src/main/java/fr/xephi/authme/service/SessionState.java b/src/main/java/fr/xephi/authme/service/SessionState.java deleted file mode 100644 index 801f36bc..00000000 --- a/src/main/java/fr/xephi/authme/service/SessionState.java +++ /dev/null @@ -1,13 +0,0 @@ -package fr.xephi.authme.service; - -public enum SessionState { - - VALID, - - NOT_VALID, - - OUTDATED, - - IP_CHANGED - -} diff --git a/src/main/java/fr/xephi/authme/service/TeleportationService.java b/src/main/java/fr/xephi/authme/service/TeleportationService.java deleted file mode 100644 index c50b0129..00000000 --- a/src/main/java/fr/xephi/authme/service/TeleportationService.java +++ /dev/null @@ -1,200 +0,0 @@ -package fr.xephi.authme.service; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.auth.PlayerAuth; -import fr.xephi.authme.data.auth.PlayerCache; -import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.events.AbstractTeleportEvent; -import fr.xephi.authme.events.AuthMeTeleportEvent; -import fr.xephi.authme.events.FirstSpawnTeleportEvent; -import fr.xephi.authme.events.SpawnTeleportEvent; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.SpawnLoader; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.TeleportUtils; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.util.HashSet; -import java.util.Set; - -import static fr.xephi.authme.settings.properties.RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN; - -/** - * Handles teleportation (placement of player to spawn). - */ -public class TeleportationService implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(TeleportationService.class); - - @Inject - private Settings settings; - - @Inject - private BukkitService bukkitService; - - @Inject - private SpawnLoader spawnLoader; - - @Inject - private PlayerCache playerCache; - - @Inject - private DataSource dataSource; - - private Set spawnOnLoginWorlds; - - TeleportationService() { - } - - @PostConstruct - @Override - public void reload() { - // Use a Set for better performance with #contains() - spawnOnLoginWorlds = new HashSet<>(settings.getProperty(RestrictionSettings.FORCE_SPAWN_ON_WORLDS)); - } - - /** - * Teleports the player according to the settings when he joins. - * - * @param player the player to process - */ - public void teleportOnJoin(final Player player) { - if (!settings.getProperty(RestrictionSettings.NO_TELEPORT) - && settings.getProperty(TELEPORT_UNAUTHED_TO_SPAWN)) { - logger.debug("Teleport on join for player `{0}`", player.getName()); - teleportToSpawn(player, playerCache.isAuthenticated(player.getName())); - } - } - - /** - * Returns the player's custom on join location. - * - * @param player the player to process - * - * @return the custom spawn location, null if the player should spawn at the original location - */ - public Location prepareOnJoinSpawnLocation(final Player player) { - if (!settings.getProperty(RestrictionSettings.NO_TELEPORT) - && settings.getProperty(TELEPORT_UNAUTHED_TO_SPAWN)) { - final Location location = spawnLoader.getSpawnLocation(player); - - SpawnTeleportEvent event = new SpawnTeleportEvent(player, location, - playerCache.isAuthenticated(player.getName())); - bukkitService.callEvent(event); - if (!isEventValid(event)) { - return null; - } - - logger.debug("Returning custom location for >1.9 join event for player `{0}`", player.getName()); - return location; - } - return null; - } - - /** - * Teleports the player to the first spawn if he is new and the first spawn is configured. - * - * @param player the player to process - */ - public void teleportNewPlayerToFirstSpawn(final Player player) { - if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { - return; - } - - Location firstSpawn = spawnLoader.getFirstSpawn(); - if (firstSpawn == null) { - return; - } - - if (!player.hasPlayedBefore() || !dataSource.isAuthAvailable(player.getName())) { - logger.debug("Attempting to teleport player `{0}` to first spawn", player.getName()); - performTeleportation(player, new FirstSpawnTeleportEvent(player, firstSpawn)); - } - } - - /** - * Teleports the player according to the settings after having successfully logged in. - * - * @param player the player - * @param auth corresponding PlayerAuth object - * @param limbo corresponding LimboPlayer object - */ - public void teleportOnLogin(final Player player, PlayerAuth auth, LimboPlayer limbo) { - if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) { - return; - } - - // #856: If LimboPlayer comes from a persisted file, the Location might be null - String worldName = (limbo != null && limbo.getLocation() != null) - ? limbo.getLocation().getWorld().getName() - : null; - - // The world in LimboPlayer is from where the player comes, before any teleportation by AuthMe - if (mustForceSpawnAfterLogin(worldName)) { - logger.debug("Teleporting `{0}` to spawn because of 'force-spawn after login'", player.getName()); - teleportToSpawn(player, true); - } else if (settings.getProperty(TELEPORT_UNAUTHED_TO_SPAWN)) { - if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) { - Location location = buildLocationFromAuth(player, auth); - Location playerLoc = player.getLocation(); - if (location.getX() == playerLoc.getX() && location.getY() == location.getY() && location.getZ() == playerLoc.getZ() - && location.getWorld() == playerLoc.getWorld()) return; - logger.debug("Teleporting `{0}` after login, based on the player auth", player.getName()); - teleportBackFromSpawn(player, location); - } else if (limbo != null && limbo.getLocation() != null) { - logger.debug("Teleporting `{0}` after login, based on the limbo player", player.getName()); - teleportBackFromSpawn(player, limbo.getLocation()); - } - } - } - - private boolean mustForceSpawnAfterLogin(String worldName) { - return worldName != null && settings.getProperty(RestrictionSettings.FORCE_SPAWN_LOCATION_AFTER_LOGIN) - && spawnOnLoginWorlds.contains(worldName); - } - - private Location buildLocationFromAuth(Player player, PlayerAuth auth) { - World world = bukkitService.getWorld(auth.getWorld()); - if (world == null) { - world = player.getWorld(); - } - return new Location(world, auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), - auth.getYaw(), auth.getPitch()); - } - - private void teleportBackFromSpawn(final Player player, final Location location) { - performTeleportation(player, new AuthMeTeleportEvent(player, location)); - } - - private void teleportToSpawn(final Player player, final boolean isAuthenticated) { - final Location spawnLoc = spawnLoader.getSpawnLocation(player); - performTeleportation(player, new SpawnTeleportEvent(player, spawnLoc, isAuthenticated)); - } - - /** - * Emits the teleportation event and performs teleportation according to it (potentially modified - * by external listeners). Note that no teleportation is performed if the event's location is empty. - * - * @param player the player to teleport - * @param event the event to emit and according to which to teleport - */ - private void performTeleportation(final Player player, final AbstractTeleportEvent event) { - bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> { - bukkitService.callEvent(event); - if (player.isOnline() && isEventValid(event)) { - TeleportUtils.teleport(player, event.getTo()); - } - }); - } - - private static boolean isEventValid(AbstractTeleportEvent event) { - return !event.isCancelled() && event.getTo() != null && event.getTo().getWorld() != null; - } -} diff --git a/src/main/java/fr/xephi/authme/service/ValidationService.java b/src/main/java/fr/xephi/authme/service/ValidationService.java deleted file mode 100644 index fca9eb53..00000000 --- a/src/main/java/fr/xephi/authme/service/ValidationService.java +++ /dev/null @@ -1,339 +0,0 @@ -package fr.xephi.authme.service; - -import ch.jalu.configme.properties.Property; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerStatePermission; -import fr.xephi.authme.security.HashUtils; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.ProtectionSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.Utils; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.DataInputStream; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.URL; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.regex.Pattern; - -import static fr.xephi.authme.util.StringUtils.isInsideString; - -/** - * Validation service. - */ -public class ValidationService implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(ValidationService.class); - - @Inject - private Settings settings; - @Inject - private DataSource dataSource; - @Inject - private PermissionsManager permissionsManager; - @Inject - private GeoIpService geoIpService; - - private Pattern passwordRegex; - private Pattern emailRegex; - private Multimap restrictedNames; - - ValidationService() { - } - - @PostConstruct - @Override - public void reload() { - passwordRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX)); - restrictedNames = settings.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS) - ? loadNameRestrictions(settings.getProperty(RestrictionSettings.RESTRICTED_USERS)) - : HashMultimap.create(); - - emailRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_EMAIL_REGEX)); - } - - /** - * 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 the validation result - */ - public ValidationResult validatePassword(String password, String username) { - String passLow = password.toLowerCase(Locale.ROOT); - if (!passwordRegex.matcher(passLow).matches()) { - return new ValidationResult(MessageKey.PASSWORD_CHARACTERS_ERROR, passwordRegex.pattern()); - } else if (passLow.equalsIgnoreCase(username)) { - return new ValidationResult(MessageKey.PASSWORD_IS_USERNAME_ERROR); - } else if (password.length() < settings.getProperty(SecuritySettings.MIN_PASSWORD_LENGTH) - || password.length() > settings.getProperty(SecuritySettings.MAX_PASSWORD_LENGTH)) { - return new ValidationResult(MessageKey.INVALID_PASSWORD_LENGTH); - } else if (settings.getProperty(SecuritySettings.UNSAFE_PASSWORDS).contains(passLow)) { - return new ValidationResult(MessageKey.PASSWORD_UNSAFE_ERROR); - } else if (settings.getProperty(SecuritySettings.HAVE_I_BEEN_PWNED_CHECK)) { - HaveIBeenPwnedResults results = validatePasswordHaveIBeenPwned(password); - if (results != null - && results.isPwned() - && results.getPwnCount() > settings.getProperty(SecuritySettings.HAVE_I_BEEN_PWNED_LIMIT)) { - return new ValidationResult(MessageKey.PASSWORD_PWNED_ERROR, String.valueOf(results.getPwnCount())); - } - } - - return new ValidationResult(); - } - - /** - * Verifies whether the email is valid and admitted for use according to the plugin settings. - * - * @param email the email to verify - * @return true if the email is valid, false otherwise - */ - public boolean validateEmail(String email) { - return emailRegex.matcher(email).matches(); - } - - /** - * Queries the database whether the email is still free for registration, i.e. whether the given - * command sender may use the email to register a new account (as defined by settings and permissions). - * - * @param email the email to verify - * @param sender the command sender - * @return true if the email may be used, false otherwise (registration threshold has been exceeded) - */ - public boolean isEmailFreeForRegistration(String email, CommandSender sender) { - return permissionsManager.hasPermission(sender, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) - || dataSource.countAuthsByEmail(email) < settings.getProperty(EmailSettings.MAX_REG_PER_EMAIL); - } - - /** - * Checks whether the player's country is allowed to join the server, based on the given IP address - * and the configured country whitelist or blacklist. - * - * @param hostAddress the IP address to verify - * @return true if the IP address' country is allowed, false otherwise - */ - public boolean isCountryAdmitted(String hostAddress) { - // Check if we have restrictions on country, if not return true and avoid the country lookup - if (settings.getProperty(ProtectionSettings.COUNTRIES_WHITELIST).isEmpty() - && settings.getProperty(ProtectionSettings.COUNTRIES_BLACKLIST).isEmpty()) { - return true; - } - - String countryCode = geoIpService.getCountryCode(hostAddress); - boolean isCountryAllowed = validateWhitelistAndBlacklist(countryCode, - ProtectionSettings.COUNTRIES_WHITELIST, ProtectionSettings.COUNTRIES_BLACKLIST); - logger.debug("Country code `{0}` for `{1}` is allowed: {2}", countryCode, hostAddress, isCountryAllowed); - return isCountryAllowed; - } - - /** - * Checks if the name is unrestricted according to the configured settings. - * - * @param name the name to verify - * @return true if unrestricted, false otherwise - */ - public boolean isUnrestricted(String name) { - return settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name.toLowerCase(Locale.ROOT)); - } - - /** - * Checks that the player meets any name restriction if present (IP/domain-based). - * - * @param player the player to check - * @return true if the player may join, false if the player does not satisfy the name restrictions - */ - public boolean fulfillsNameRestrictions(Player player) { - Collection restrictions = restrictedNames.get(player.getName().toLowerCase(Locale.ROOT)); - if (Utils.isCollectionEmpty(restrictions)) { - return true; - } - - String ip = PlayerUtils.getPlayerIp(player); - String domain = getHostName(player.getAddress()); - for (String restriction : restrictions) { - if (restriction.startsWith("regex:")) { - restriction = restriction.replace("regex:", ""); - } else { - restriction = restriction.replace("*", "(.*)"); - } - if (ip.matches(restriction)) { - return true; - } - if (domain.matches(restriction)) { - return true; - } - } - return false; - } - - @VisibleForTesting - protected String getHostName(InetSocketAddress inetSocketAddr) { - return inetSocketAddr.getHostName(); - } - - /** - * Verifies whether the given value is allowed according to the given whitelist and blacklist settings. - * Whitelist has precedence over blacklist: if a whitelist is set, the value is rejected if not present - * in the whitelist. - * - * @param value the value to verify - * @param whitelist the whitelist property - * @param blacklist the blacklist property - * @return true if the value is admitted by the lists, false otherwise - */ - private boolean validateWhitelistAndBlacklist(String value, Property> whitelist, - Property> blacklist) { - List whitelistValue = settings.getProperty(whitelist); - if (!Utils.isCollectionEmpty(whitelistValue)) { - return containsIgnoreCase(whitelistValue, value); - } - List blacklistValue = settings.getProperty(blacklist); - return Utils.isCollectionEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value); - } - - private static boolean containsIgnoreCase(Collection coll, String needle) { - for (String entry : coll) { - if (entry.equalsIgnoreCase(needle)) { - return true; - } - } - return false; - } - - /** - * Loads the configured name restrictions into a Multimap by player name (all-lowercase). - * - * @param configuredRestrictions the restriction rules to convert to a map - * @return map of allowed IPs/domain names by player name - */ - private Multimap loadNameRestrictions(Set configuredRestrictions) { - Multimap restrictions = HashMultimap.create(); - for (String restriction : configuredRestrictions) { - if (isInsideString(';', restriction)) { - String[] data = restriction.split(";"); - restrictions.put(data[0].toLowerCase(Locale.ROOT), data[1]); - } else { - logger.warning("Restricted user rule must have a ';' separating name from restriction," - + " but found: '" + restriction + "'"); - } - } - return restrictions; - } - /** - * Check haveibeenpwned.com for the given password. - * - * @param password password to check for - * @return Results of the check - */ - public HaveIBeenPwnedResults validatePasswordHaveIBeenPwned(String password) { - String hash = HashUtils.sha1(password); - - String hashPrefix = hash.substring(0, 5); - - try { - String url = String.format("https://api.pwnedpasswords.com/range/%s", hashPrefix); - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("User-Agent", "AuthMeReloaded"); - connection.setConnectTimeout(5000); - connection.setReadTimeout(5000); - connection.setDoInput(true); - StringBuilder outStr = new StringBuilder(); - - try (DataInputStream input = new DataInputStream(connection.getInputStream())) { - for (int c = input.read(); c != -1; c = input.read()) - outStr.append((char) c); - } - - String[] hashes = outStr.toString().split("\n"); - for (String hashSuffix : hashes) { - String[] hashSuffixParts = hashSuffix.trim().split(":"); - if (hashSuffixParts[0].equalsIgnoreCase(hash.substring(5))) { - return new HaveIBeenPwnedResults(true, Integer.parseInt(hashSuffixParts[1])); - } - } - return new HaveIBeenPwnedResults(false, 0); - } catch (java.io.IOException e) { - logger.warning("Error occurred while checking password online, check your connection.\nWhen this error shows, the player's password won't be check"); - return null; - } - } - - - public static final class ValidationResult { - private final MessageKey messageKey; - private final String[] args; - - /** - * Constructor for a successful validation. - */ - public ValidationResult() { - this.messageKey = null; - this.args = null; - } - - /** - * Constructor for a failed validation. - * - * @param messageKey message key of the validation error - * @param args arguments for the message key - */ - public ValidationResult(MessageKey messageKey, String... args) { - this.messageKey = messageKey; - this.args = args; - } - - /** - * Returns whether an error was found during the validation, i.e. whether the validation failed. - * - * @return true if there is an error, false if the validation was successful - */ - public boolean hasError() { - return messageKey != null; - } - - public MessageKey getMessageKey() { - return messageKey; - } - - public String[] getArgs() { - return args; - } - } - - public static final class HaveIBeenPwnedResults { - private final boolean isPwned; - private final int pwnCount; - - public HaveIBeenPwnedResults(boolean isPwned, int pwnCount) { - this.isPwned = isPwned; - this.pwnCount = pwnCount; - } - - public boolean isPwned() { - return isPwned; - } - - public int getPwnCount() { - return pwnCount; - } - } -} diff --git a/src/main/java/fr/xephi/authme/service/bungeecord/BungeeReceiver.java b/src/main/java/fr/xephi/authme/service/bungeecord/BungeeReceiver.java deleted file mode 100644 index 05c7c944..00000000 --- a/src/main/java/fr/xephi/authme/service/bungeecord/BungeeReceiver.java +++ /dev/null @@ -1,160 +0,0 @@ -package fr.xephi.authme.service.bungeecord; - -import com.google.common.io.ByteArrayDataInput; -import com.google.common.io.ByteStreams; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.ProxySessionManager; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.Messenger; -import org.bukkit.plugin.messaging.PluginMessageListener; - -import javax.inject.Inject; -import java.util.Optional; - -public class BungeeReceiver implements PluginMessageListener, SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(BungeeReceiver.class); - - private final AuthMe plugin; - private final BukkitService bukkitService; - private final ProxySessionManager proxySessionManager; - private final Management management; - - private boolean isEnabled; - - @Inject - BungeeReceiver(AuthMe plugin, BukkitService bukkitService, ProxySessionManager proxySessionManager, - Management management, Settings settings) { - this.plugin = plugin; - this.bukkitService = bukkitService; - this.proxySessionManager = proxySessionManager; - this.management = management; - reload(settings); - } - - @Override - public void reload(Settings settings) { - this.isEnabled = settings.getProperty(HooksSettings.BUNGEECORD); - if (this.isEnabled) { - this.isEnabled = bukkitService.isBungeeCordConfiguredForSpigot().orElse(false); - } - if (this.isEnabled) { - final Messenger messenger = plugin.getServer().getMessenger(); - if (!messenger.isIncomingChannelRegistered(plugin, "BungeeCord")) { - messenger.registerIncomingPluginChannel(plugin, "BungeeCord", this); - } - } - } - - /** - * Processes the given data input and attempts to translate it to a message for the "AuthMe.v2.Broadcast" channel. - * - * @param in the input to handle - */ - private void handleBroadcast(ByteArrayDataInput in) { - // Read data byte array - short dataLength = in.readShort(); - byte[] dataBytes = new byte[dataLength]; - in.readFully(dataBytes); - ByteArrayDataInput dataIn = ByteStreams.newDataInput(dataBytes); - - // Parse type - String typeId = dataIn.readUTF(); - Optional type = MessageType.fromId(typeId); - if (!type.isPresent()) { - logger.debug("Received unsupported forwarded bungeecord message type! ({0})", typeId); - return; - } - - // Parse argument - String argument; - try { - argument = dataIn.readUTF(); - } catch (IllegalStateException e) { - logger.warning("Received invalid forwarded plugin message of type " + type.get().name() - + ": argument is missing!"); - return; - } - - // Handle type - switch (type.get()) { - case LOGIN: - case LOGOUT: - // TODO: unused - break; - default: - } - } - - /** - * Processes the given data input and attempts to translate it to a message for the "AuthMe.v2" channel. - * - * @param in the input to handle - */ - private void handle(ByteArrayDataInput in) { - // Parse type - String typeId = in.readUTF(); - Optional type = MessageType.fromId(typeId); - if (!type.isPresent()) { - logger.debug("Received unsupported bungeecord message type! ({0})", typeId); - return; - } - - // Parse argument - String argument; - try { - argument = in.readUTF(); - } catch (IllegalStateException e) { - logger.warning("Received invalid plugin message of type " + type.get().name() - + ": argument is missing!"); - return; - } - - // Handle type - switch (type.get()) { - case PERFORM_LOGIN: - performLogin(argument); - break; - default: - } - } - - @Override - public void onPluginMessageReceived(String channel, Player player, byte[] data) { - if (!isEnabled) { - return; - } - - ByteArrayDataInput in = ByteStreams.newDataInput(data); - - // Check subchannel - String subChannel = in.readUTF(); - if ("AuthMe.v2.Broadcast".equals(subChannel)) { - handleBroadcast(in); - } else if ("AuthMe.v2".equals(subChannel)) { - handle(in); - } - } - - private void performLogin(String name) { - Player player = bukkitService.getPlayerExact(name); - if (player != null && player.isOnline()) { - management.forceLogin(player, true); - logger.info("The user " + player.getName() + " has been automatically logged in, " - + "as requested via plugin messaging."); - } else { - proxySessionManager.processProxySessionMessage(name); - logger.info("The user " + name + " should be automatically logged in, " - + "as requested via plugin messaging but has not been detected, nickname has been" - + " added to autologin queue."); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java b/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java deleted file mode 100644 index 3d43605b..00000000 --- a/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java +++ /dev/null @@ -1,113 +0,0 @@ -package fr.xephi.authme.service.bungeecord; - -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.Messenger; - -import javax.inject.Inject; -import java.util.Locale; - -public class BungeeSender implements SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(BungeeSender.class); - private final AuthMe plugin; - private final BukkitService bukkitService; - - private boolean isEnabled; - private String destinationServerOnLogin; - - /* - * Constructor. - */ - @Inject - BungeeSender(AuthMe plugin, BukkitService bukkitService, Settings settings) { - this.plugin = plugin; - this.bukkitService = bukkitService; - reload(settings); - } - - @Override - public void reload(Settings settings) { - this.isEnabled = settings.getProperty(HooksSettings.BUNGEECORD); - this.destinationServerOnLogin = settings.getProperty(HooksSettings.BUNGEECORD_SERVER); - - if (this.isEnabled) { - Messenger messenger = plugin.getServer().getMessenger(); - if (!messenger.isOutgoingChannelRegistered(plugin, "BungeeCord")) { - messenger.registerOutgoingPluginChannel(plugin, "BungeeCord"); - } - } - } - - public boolean isEnabled() { - return isEnabled; - } - - private void sendBungeecordMessage(Player player, String... data) { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - for (String element : data) { - out.writeUTF(element); - } - bukkitService.sendBungeeMessage(player, out.toByteArray()); - } - - private void sendForwardedBungeecordMessage(Player player, String subChannel, String... data) { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("Forward"); - out.writeUTF("ONLINE"); - out.writeUTF(subChannel); - ByteArrayDataOutput dataOut = ByteStreams.newDataOutput(); - for (String element : data) { - dataOut.writeUTF(element); - } - byte[] dataBytes = dataOut.toByteArray(); - out.writeShort(dataBytes.length); - out.write(dataBytes); - bukkitService.sendBungeeMessage(player, out.toByteArray()); - } - - /** - * Send a player to a specified server. If no server is configured, this will - * do nothing. - * - * @param player The player to send. - */ - public void connectPlayerOnLogin(Player player) { - if (!isEnabled || destinationServerOnLogin.isEmpty()) { - return; - } - // Add a small delay, just in case... - bukkitService.scheduleSyncDelayedTask(() -> - sendBungeecordMessage(player, "Connect", destinationServerOnLogin), 10L); - } - - /** - * Sends a message to the AuthMe plugin messaging channel, if enabled. - * - * @param player The player related to the message - * @param type The message type, See {@link MessageType} - */ - public void sendAuthMeBungeecordMessage(Player player, MessageType type) { - if (!isEnabled) { - return; - } - if (!plugin.isEnabled()) { - logger.debug("Tried to send a " + type + " bungeecord message but the plugin was disabled!"); - return; - } - if (type.isBroadcast()) { - sendForwardedBungeecordMessage(player, "AuthMe.v2.Broadcast", type.getId(), player.getName().toLowerCase(Locale.ROOT)); - } else { - sendBungeecordMessage(player, "AuthMe.v2", type.getId(), player.getName().toLowerCase(Locale.ROOT)); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/service/bungeecord/MessageType.java b/src/main/java/fr/xephi/authme/service/bungeecord/MessageType.java deleted file mode 100644 index ac63e41e..00000000 --- a/src/main/java/fr/xephi/authme/service/bungeecord/MessageType.java +++ /dev/null @@ -1,42 +0,0 @@ -package fr.xephi.authme.service.bungeecord; - -import java.util.Optional; - -public enum MessageType { - LOGIN("login", true), - LOGOUT("logout", true), - PERFORM_LOGIN("perform.login", false); - - private final String id; - private final boolean broadcast; - - MessageType(String id, boolean broadcast) { - this.id = id; - this.broadcast = broadcast; - } - - public String getId() { - return id; - } - - public boolean isBroadcast() { - return broadcast; - } - - /** - * Returns the MessageType with the given ID. - * - * @param id the message type id. - * - * @return the MessageType with the given id, empty if invalid. - */ - public static Optional fromId(String id) { - for (MessageType current : values()) { - if (current.getId().equals(id)) { - return Optional.of(current); - } - } - return Optional.empty(); - } - -} diff --git a/src/main/java/fr/xephi/authme/service/velocity/VMessageType.java b/src/main/java/fr/xephi/authme/service/velocity/VMessageType.java deleted file mode 100644 index 0e65db42..00000000 --- a/src/main/java/fr/xephi/authme/service/velocity/VMessageType.java +++ /dev/null @@ -1,5 +0,0 @@ -package fr.xephi.authme.service.velocity; - -public enum VMessageType { - LOGIN, REGISTER, LOGOUT, FORCE_UNREGISTER, UNREGISTER -} diff --git a/src/main/java/fr/xephi/authme/service/velocity/VelocityReceiver.java b/src/main/java/fr/xephi/authme/service/velocity/VelocityReceiver.java deleted file mode 100644 index caa04e5f..00000000 --- a/src/main/java/fr/xephi/authme/service/velocity/VelocityReceiver.java +++ /dev/null @@ -1,89 +0,0 @@ -package fr.xephi.authme.service.velocity; - -import com.google.common.io.ByteArrayDataInput; -import com.google.common.io.ByteStreams; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.data.ProxySessionManager; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.process.Management; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.Messenger; -import org.bukkit.plugin.messaging.PluginMessageListener; - -import javax.inject.Inject; - -public class VelocityReceiver implements PluginMessageListener, SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(VelocityReceiver.class); - - private final AuthMe plugin; - private final BukkitService bukkitService; - private final ProxySessionManager proxySessionManager; - private final Management management; - - private boolean isEnabled; - - @Inject - VelocityReceiver(AuthMe plugin, BukkitService bukkitService, ProxySessionManager proxySessionManager, - Management management, Settings settings) { - this.plugin = plugin; - this.bukkitService = bukkitService; - this.proxySessionManager = proxySessionManager; - this.management = management; - reload(settings); - } - - @Override - public void reload(Settings settings) { - this.isEnabled = settings.getProperty(HooksSettings.VELOCITY); - if (this.isEnabled) { - final Messenger messenger = plugin.getServer().getMessenger(); - if (!messenger.isIncomingChannelRegistered(plugin, "authmevelocity:main")) { - messenger.registerIncomingPluginChannel(plugin, "authmevelocity:main", this); - } - } - } - - - @Override - public void onPluginMessageReceived(String channel, Player player, byte[] bytes) { - if (!isEnabled) { - return; - } - - if (channel.equals("authmevelocity:main")) { - final ByteArrayDataInput in = ByteStreams.newDataInput(bytes); - - final String data = in.readUTF(); - final String username = in.readUTF(); - processData(username, data); - logger.debug("PluginMessage | AuthMeVelocity identifier processed"); - } - } - - private void processData(String username, String data) { - if (VMessageType.LOGIN.toString().equals(data)) { - performLogin(username); - } - } - - private void performLogin(String name) { - Player player = bukkitService.getPlayerExact(name); - if (player != null && player.isOnline()) { - management.forceLogin(player, true); - logger.info("The user " + player.getName() + " has been automatically logged in, " - + "as requested via plugin messaging."); - } else { - proxySessionManager.processProxySessionMessage(name); - logger.info("The user " + name + " should be automatically logged in, " - + "as requested via plugin messaging but has not been detected, nickname has been" - + " added to autologin queue."); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/service/velocity/VelocitySender.java b/src/main/java/fr/xephi/authme/service/velocity/VelocitySender.java deleted file mode 100644 index 16a0f2cb..00000000 --- a/src/main/java/fr/xephi/authme/service/velocity/VelocitySender.java +++ /dev/null @@ -1,76 +0,0 @@ -package fr.xephi.authme.service.velocity; - -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.bungeecord.MessageType; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.HooksSettings; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.Messenger; - -import javax.inject.Inject; - -public class VelocitySender implements SettingsDependent { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(VelocitySender.class); - private final AuthMe plugin; - private final BukkitService bukkitService; - - private boolean isEnabled; - - /* - * Constructor. - */ - @Inject - VelocitySender(AuthMe plugin, BukkitService bukkitService, Settings settings) { - this.plugin = plugin; - this.bukkitService = bukkitService; - reload(settings); - } - - @Override - public void reload(Settings settings) { - this.isEnabled = settings.getProperty(HooksSettings.VELOCITY); - - if (this.isEnabled) { - Messenger messenger = plugin.getServer().getMessenger(); - if (!messenger.isOutgoingChannelRegistered(plugin, "authmevelocity:main")) { - messenger.registerOutgoingPluginChannel(plugin, "authmevelocity:main"); - } - } - } - - public boolean isEnabled() { - return isEnabled; - } - - private void sendForwardedVelocityMessage(Player player, VMessageType type, String playerName) { - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF(type.toString()); - out.writeUTF(playerName); - bukkitService.sendVelocityMessage(player, out.toByteArray()); - } - - /** - * Sends a message to the AuthMe plugin messaging channel, if enabled. - * - * @param player The player related to the message - * @param type The message type, See {@link MessageType} - */ - public void sendAuthMeVelocityMessage(Player player, VMessageType type) { - if (!isEnabled) { - return; - } - if (!plugin.isEnabled()) { - logger.debug("Tried to send a " + type + " velocity message but the plugin was disabled!"); - return; - } - sendForwardedVelocityMessage(player, type, player.getName()); - } - -} diff --git a/src/main/java/fr/xephi/authme/service/yaml/YamlFileResourceProvider.java b/src/main/java/fr/xephi/authme/service/yaml/YamlFileResourceProvider.java deleted file mode 100644 index 9509d730..00000000 --- a/src/main/java/fr/xephi/authme/service/yaml/YamlFileResourceProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -package fr.xephi.authme.service.yaml; - -import ch.jalu.configme.exception.ConfigMeException; -import ch.jalu.configme.resource.PropertyReader; -import ch.jalu.configme.resource.YamlFileResource; - -import java.io.File; - -/** - * Creates {@link YamlFileResource} objects. - */ -public final class YamlFileResourceProvider { - - private YamlFileResourceProvider() { - } - - /** - * Creates a {@link YamlFileResource} instance for the given file. Wraps SnakeYAML's parse exception - * thrown when a reader is created into an AuthMe exception. - * - * @param file the file to load - * @return the generated resource - */ - public static YamlFileResource loadFromFile(File file) { - return new AuthMeYamlFileResource(file); - } - - /** - * Extension of {@link YamlFileResource} which wraps SnakeYAML's parse exception into a custom - * exception when a reader is created. - */ - private static final class AuthMeYamlFileResource extends YamlFileResource { - - AuthMeYamlFileResource(File file) { - super(file); - } - - @Override - public PropertyReader createReader() { - try { - return super.createReader(); - } catch (ConfigMeException e) { - throw new YamlParseException(getFile().getPath(), e); - } - } - } -} diff --git a/src/main/java/fr/xephi/authme/service/yaml/YamlParseException.java b/src/main/java/fr/xephi/authme/service/yaml/YamlParseException.java deleted file mode 100644 index eba631d3..00000000 --- a/src/main/java/fr/xephi/authme/service/yaml/YamlParseException.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.xephi.authme.service.yaml; - -import ch.jalu.configme.exception.ConfigMeException; - -import java.util.Optional; - -/** - * Exception when a YAML file could not be parsed. - */ -public class YamlParseException extends RuntimeException { - - private final String file; - - /** - * Constructor. - * - * @param file the file a parsing exception occurred with - * @param configMeException the caught exception from ConfigMe - */ - public YamlParseException(String file, ConfigMeException configMeException) { - super(Optional.ofNullable(configMeException.getCause()).orElse(configMeException)); - this.file = file; - } - - public String getFile() { - return file; - } -} diff --git a/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java b/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java deleted file mode 100644 index 583be062..00000000 --- a/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.xephi.authme.settings; - -import ch.jalu.configme.properties.BaseProperty; -import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; -import ch.jalu.configme.resource.PropertyReader; - -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import static com.google.common.collect.Sets.newHashSet; - -/** - * Property whose value is a set of entries of a given enum. - * - * @param the enum type - */ -public class EnumSetProperty> extends BaseProperty> { - - private final Class enumClass; - - @SafeVarargs - public EnumSetProperty(Class enumClass, String path, E... values) { - super(path, newHashSet(values)); - this.enumClass = enumClass; - } - - @Override - protected Set getFromReader(PropertyReader reader, ConvertErrorRecorder errorRecorder) { - Object entry = reader.getObject(getPath()); - if (entry instanceof Collection) { - return ((Collection) entry).stream() - .map(val -> toEnum(String.valueOf(val))) - .filter(e -> e != null) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - return null; - } - - private E toEnum(String str) { - for (E e : enumClass.getEnumConstants()) { - if (str.equalsIgnoreCase(e.name())) { - return e; - } - } - return null; - } - - @Override - public Object toExportValue(Set value) { - return value.stream() - .map(Enum::name) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java deleted file mode 100644 index ad0afa6f..00000000 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ /dev/null @@ -1,113 +0,0 @@ -package fr.xephi.authme.settings; - -import ch.jalu.configme.SettingsManagerImpl; -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.migration.MigrationService; -import ch.jalu.configme.resource.PropertyResource; -import com.google.common.io.Files; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import static fr.xephi.authme.util.FileUtils.copyFileFromResource; - -/** - * The AuthMe settings manager. - */ -public class Settings extends SettingsManagerImpl { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(Settings.class); - private final File pluginFolder; - private String passwordEmailMessage; - private String verificationEmailMessage; - private String recoveryCodeEmailMessage; - private String shutdownEmailMessage; - private String newPasswordEmailMessage; - - - /** - * Constructor. - * - * @param pluginFolder the AuthMe plugin folder - * @param resource the property resource to read and write properties to - * @param migrationService migration service to check the settings file with - * @param configurationData configuration data (properties and comments) - */ - public Settings(File pluginFolder, PropertyResource resource, MigrationService migrationService, - ConfigurationData configurationData) { - super(resource, configurationData, migrationService); - this.pluginFolder = pluginFolder; - loadSettingsFromFiles(); - } - - /** - * Return the text to use in email registrations. - * - * @return The email message - */ - public String getPasswordEmailMessage() { - return passwordEmailMessage; - } - - /** - * Return the text for verification emails (before sensitive commands can be used). - * - * @return The email message - */ - public String getVerificationEmailMessage() { - return verificationEmailMessage; - } - - /** - * Return the text to use when someone requests to receive a recovery code. - * - * @return The email message - */ - public String getRecoveryCodeEmailMessage() { - return recoveryCodeEmailMessage; - } - - public String getShutdownEmailMessage() {return shutdownEmailMessage;} - - public String getNewPasswordEmailMessage() { - return newPasswordEmailMessage; - } - - private void loadSettingsFromFiles() { - newPasswordEmailMessage = readFile("new_email.html"); - passwordEmailMessage = readFile("email.html"); - verificationEmailMessage = readFile("verification_code_email.html"); - recoveryCodeEmailMessage = readFile("recovery_code_email.html"); - shutdownEmailMessage = readFile("shutdown.html"); - String country = readFile("GeoLite2-Country.mmdb"); - } - - @Override - public void reload() { - super.reload(); - loadSettingsFromFiles(); - } - - /** - * Reads a file from the plugin folder or copies it from the JAR to the plugin folder. - * - * @param filename the file to read - * @return the file's contents - */ - private String readFile(String filename) { - final File file = new File(pluginFolder, filename); - if (copyFileFromResource(file, filename)) { - try { - return Files.asCharSource(file, StandardCharsets.UTF_8).read(); - } catch (IOException e) { - logger.logException("Failed to read file '" + filename + "':", e); - } - } else { - logger.warning("Failed to copy file '" + filename + "' from JAR"); - } - return ""; - } -} diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java deleted file mode 100644 index fe035a8b..00000000 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ /dev/null @@ -1,400 +0,0 @@ -package fr.xephi.authme.settings; - -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.migration.PlainMigrationService; -import ch.jalu.configme.properties.Property; -import ch.jalu.configme.properties.convertresult.PropertyValue; -import ch.jalu.configme.resource.PropertyReader; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSourceType; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.output.LogLevel; -import fr.xephi.authme.process.register.RegisterSecondaryArgument; -import fr.xephi.authme.process.register.RegistrationType; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.settings.properties.DatabaseSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RegistrationSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; -import fr.xephi.authme.util.StringUtils; - -import javax.inject.Inject; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static ch.jalu.configme.properties.PropertyInitializer.newListProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; -import static fr.xephi.authme.settings.properties.DatabaseSettings.MYSQL_POOL_SIZE; -import static fr.xephi.authme.settings.properties.RegistrationSettings.DELAY_JOIN_MESSAGE; -import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_JOIN_MESSAGE; -import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_LEAVE_MESSAGE; -import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS; -import static fr.xephi.authme.settings.properties.RestrictionSettings.FORCE_SPAWN_LOCATION_AFTER_LOGIN; -import static fr.xephi.authme.settings.properties.RestrictionSettings.FORCE_SPAWN_ON_WORLDS; - -/** - * Service for verifying that the configuration is up-to-date. - */ -public class SettingsMigrationService extends PlainMigrationService { - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(SettingsMigrationService.class); - private final File pluginFolder; - - // Stores old "other accounts command" config if present. - // We need to store it in here for retrieval when we build the CommandConfig. Retrieving it from the config.yml is - // not possible since this migration service may trigger the config.yml to be resaved. As the old command settings - // don't exist in the code anymore, as soon as config.yml is resaved we lose this information. - private String oldOtherAccountsCommand; - private int oldOtherAccountsCommandThreshold; - - @Inject - SettingsMigrationService(@DataFolder File pluginFolder) { - this.pluginFolder = pluginFolder; - } - - @Override - @SuppressWarnings("checkstyle:BooleanExpressionComplexity") - protected boolean performMigrations(PropertyReader reader, ConfigurationData configurationData) { - boolean changes = false; - - if ("[a-zA-Z0-9_?]*".equals(reader.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) { - configurationData.setValue(ALLOWED_NICKNAME_CHARACTERS, "[a-zA-Z0-9_]*"); - changes = true; - } - - String driverClass = reader.getString("DataSource.mySQLDriverClassName"); - if ("fr.xephi.authme.libs.org.mariadb.jdbc.Driver".equals(driverClass)) { - configurationData.setValue(DatabaseSettings.BACKEND, DataSourceType.MARIADB); - changes = true; - } - - setOldOtherAccountsCommandFieldsIfSet(reader); - - // Note ljacqu 20160211: Concatenating migration methods with | instead of the usual || - // ensures that all migrations will be performed - return changes - | performMailTextToFileMigration(reader) - | migrateJoinLeaveMessages(reader, configurationData) - | migrateForceSpawnSettings(reader, configurationData) - | migratePoolSizeSetting(reader, configurationData) - | changeBooleanSettingToLogLevelProperty(reader, configurationData) - | hasOldHelpHeaderProperty(reader) - | hasSupportOldPasswordProperty(reader) - | convertToRegistrationType(reader, configurationData) - | mergeAndMovePermissionGroupSettings(reader, configurationData) - | moveDeprecatedHashAlgorithmIntoLegacySection(reader, configurationData) - | moveSaltColumnConfigWithOtherColumnConfigs(reader, configurationData) - || hasDeprecatedProperties(reader); - } - - private static boolean hasDeprecatedProperties(PropertyReader reader) { - String[] deprecatedProperties = { - "Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications", - "Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt", - "VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite", - "Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping", - "settings.restrictions.keepCollisionsDisabled", "settings.forceCommands", "settings.forceCommandsAsConsole", - "settings.forceRegisterCommands", "settings.forceRegisterCommandsAsConsole", - "settings.sessions.sessionExpireOnIpChange", "settings.restrictions.otherAccountsCmd", - "settings.restrictions.otherAccountsCmdThreshold, DataSource.mySQLDriverClassName"}; - for (String deprecatedPath : deprecatedProperties) { - if (reader.contains(deprecatedPath)) { - return true; - } - } - return false; - } - - // -------- - // Old other accounts - // -------- - public boolean hasOldOtherAccountsCommand() { - return !StringUtils.isBlank(oldOtherAccountsCommand); - } - - public String getOldOtherAccountsCommand() { - return oldOtherAccountsCommand; - } - - public int getOldOtherAccountsCommandThreshold() { - return oldOtherAccountsCommandThreshold; - } - - // -------- - // Specific migrations - // -------- - - /** - * Check if {@code Email.mailText} is present and move it to the Email.html file if it doesn't exist yet. - * - * @param reader The property reader - * @return True if a migration has been completed, false otherwise - */ - private boolean performMailTextToFileMigration(PropertyReader reader) { - final String oldSettingPath = "Email.mailText"; - final String oldMailText = reader.getString(oldSettingPath); - if (oldMailText == null) { - return false; - } - - final File emailFile = new File(pluginFolder, "email.html"); - final String mailText = oldMailText - .replace("", "").replace("%playername%", "") - .replace("", "").replace("%servername%", "") - .replace("", "").replace("%generatedpass%", "") - .replace("", "").replace("%image%", ""); - if (!emailFile.exists()) { - try (FileWriter fw = new FileWriter(emailFile)) { - fw.write(mailText); - } catch (IOException e) { - logger.logException("Could not create email.html configuration file:", e); - } - } - return true; - } - - /** - * Detect deprecated {@code settings.delayJoinLeaveMessages} and inform user of new "remove join messages" - * and "remove leave messages" settings. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean migrateJoinLeaveMessages(PropertyReader reader, ConfigurationData configData) { - Property oldDelayJoinProperty = newProperty("settings.delayJoinLeaveMessages", false); - boolean hasMigrated = moveProperty(oldDelayJoinProperty, DELAY_JOIN_MESSAGE, reader, configData); - - if (hasMigrated) { - logger.info(String.format("Note that we now also have the settings %s and %s", - REMOVE_JOIN_MESSAGE.getPath(), REMOVE_LEAVE_MESSAGE.getPath())); - } - return hasMigrated; - } - - /** - * Detects old "force spawn loc on join" and "force spawn on these worlds" settings and moves them - * to the new paths. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean migrateForceSpawnSettings(PropertyReader reader, ConfigurationData configData) { - Property oldForceLocEnabled = newProperty( - "settings.restrictions.ForceSpawnLocOnJoinEnabled", false); - Property> oldForceWorlds = newListProperty( - "settings.restrictions.ForceSpawnOnTheseWorlds", "world", "world_nether", "world_the_ed"); - - return moveProperty(oldForceLocEnabled, FORCE_SPAWN_LOCATION_AFTER_LOGIN, reader, configData) - | moveProperty(oldForceWorlds, FORCE_SPAWN_ON_WORLDS, reader, configData); - } - - /** - * Detects the old auto poolSize value and replaces it with the default value. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean migratePoolSizeSetting(PropertyReader reader, ConfigurationData configData) { - Integer oldValue = reader.getInt(MYSQL_POOL_SIZE.getPath()); - if (oldValue == null || oldValue > 0) { - return false; - } - configData.setValue(MYSQL_POOL_SIZE, 10); - return true; - } - - /** - * Changes the old boolean property "hide spam from console" to the new property specifying - * the log level. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean changeBooleanSettingToLogLevelProperty(PropertyReader reader, - ConfigurationData configData) { - final String oldPath = "Security.console.noConsoleSpam"; - final Property newProperty = PluginSettings.LOG_LEVEL; - if (!newProperty.isValidInResource(reader) && reader.contains(oldPath)) { - logger.info("Moving '" + oldPath + "' to '" + newProperty.getPath() + "'"); - boolean oldValue = Optional.ofNullable(reader.getBoolean(oldPath)).orElse(false); - LogLevel level = oldValue ? LogLevel.INFO : LogLevel.FINE; - configData.setValue(newProperty, level); - return true; - } - return false; - } - - private static boolean hasOldHelpHeaderProperty(PropertyReader reader) { - if (reader.contains("settings.helpHeader")) { - logger.warning("Help header setting is now in messages/help_xx.yml, " - + "please check the file to set it again"); - return true; - } - return false; - } - - private static boolean hasSupportOldPasswordProperty(PropertyReader reader) { - String path = "settings.security.supportOldPasswordHash"; - if (reader.contains(path)) { - logger.warning("Property '" + path + "' is no longer supported. " - + "Use '" + SecuritySettings.LEGACY_HASHES.getPath() + "' instead."); - return true; - } - return false; - } - - /** - * Converts old boolean configurations for registration to the new enum properties, if applicable. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean convertToRegistrationType(PropertyReader reader, ConfigurationData configData) { - String oldEmailRegisterPath = "settings.registration.enableEmailRegistrationSystem"; - if (RegistrationSettings.REGISTRATION_TYPE.isValidInResource(reader) - || !reader.contains(oldEmailRegisterPath)) { - return false; - } - - boolean useEmail = newProperty(oldEmailRegisterPath, false).determineValue(reader).getValue(); - RegistrationType registrationType = useEmail ? RegistrationType.EMAIL : RegistrationType.PASSWORD; - - String useConfirmationPath = useEmail - ? "settings.registration.doubleEmailCheck" - : "settings.restrictions.enablePasswordConfirmation"; - boolean hasConfirmation = newProperty(useConfirmationPath, false).determineValue(reader).getValue(); - RegisterSecondaryArgument secondaryArgument = hasConfirmation - ? RegisterSecondaryArgument.CONFIRMATION - : RegisterSecondaryArgument.NONE; - - logger.warning("Merging old registration settings into '" - + RegistrationSettings.REGISTRATION_TYPE.getPath() + "'"); - configData.setValue(RegistrationSettings.REGISTRATION_TYPE, registrationType); - configData.setValue(RegistrationSettings.REGISTER_SECOND_ARGUMENT, secondaryArgument); - return true; - } - - /** - * Migrates old permission group settings to the new configurations. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean mergeAndMovePermissionGroupSettings(PropertyReader reader, ConfigurationData configData) { - boolean performedChanges; - - // We have two old settings replaced by only one: move the first non-empty one - Property oldUnloggedInGroup = newProperty("settings.security.unLoggedinGroup", ""); - Property oldRegisteredGroup = newProperty("GroupOptions.RegisteredPlayerGroup", ""); - if (!oldUnloggedInGroup.determineValue(reader).getValue().isEmpty()) { - performedChanges = moveProperty(oldUnloggedInGroup, PluginSettings.REGISTERED_GROUP, reader, configData); - } else { - performedChanges = moveProperty(oldRegisteredGroup, PluginSettings.REGISTERED_GROUP, reader, configData); - } - - // Move paths of other old options - performedChanges |= moveProperty(newProperty("GroupOptions.UnregisteredPlayerGroup", ""), - PluginSettings.UNREGISTERED_GROUP, reader, configData); - performedChanges |= moveProperty(newProperty("permission.EnablePermissionCheck", false), - PluginSettings.ENABLE_PERMISSION_CHECK, reader, configData); - return performedChanges; - } - - /** - * If a deprecated hash is used, it is added to the legacy hashes option and the active hash - * is changed to SHA256. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean moveDeprecatedHashAlgorithmIntoLegacySection(PropertyReader reader, - ConfigurationData configData) { - HashAlgorithm currentHash = SecuritySettings.PASSWORD_HASH.determineValue(reader).getValue(); - // Skip CUSTOM (has no class) and PLAINTEXT (is force-migrated later on in the startup process) - if (currentHash != HashAlgorithm.CUSTOM && currentHash != HashAlgorithm.PLAINTEXT) { - Class encryptionClass = currentHash.getClazz(); - if (encryptionClass.isAnnotationPresent(Deprecated.class)) { - configData.setValue(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); - Set legacyHashes = SecuritySettings.LEGACY_HASHES.determineValue(reader).getValue(); - legacyHashes.add(currentHash); - configData.setValue(SecuritySettings.LEGACY_HASHES, legacyHashes); - logger.warning("The hash algorithm '" + currentHash - + "' is no longer supported for active use. New hashes will be in SHA256."); - return true; - } - } - return false; - } - - /** - * Moves the property for the password salt column name to the same path as all other column name properties. - * - * @param reader The property reader - * @param configData Configuration data - * @return True if the configuration has changed, false otherwise - */ - private static boolean moveSaltColumnConfigWithOtherColumnConfigs(PropertyReader reader, - ConfigurationData configData) { - Property oldProperty = newProperty("ExternalBoardOptions.mySQLColumnSalt", - DatabaseSettings.MYSQL_COL_SALT.getDefaultValue()); - return moveProperty(oldProperty, DatabaseSettings.MYSQL_COL_SALT, reader, configData); - } - - /** - * Retrieves the old config to run a command when alt accounts are detected and sets them to this instance - * for further processing. - * - * @param reader The property reader - */ - private void setOldOtherAccountsCommandFieldsIfSet(PropertyReader reader) { - Property commandProperty = newProperty("settings.restrictions.otherAccountsCmd", ""); - Property commandThresholdProperty = newProperty("settings.restrictions.otherAccountsCmdThreshold", 0); - - PropertyValue commandPropValue = commandProperty.determineValue(reader); - int commandThreshold = commandThresholdProperty.determineValue(reader).getValue(); - if (commandPropValue.isValidInResource() && commandThreshold >= 2) { - oldOtherAccountsCommand = commandPropValue.getValue(); - oldOtherAccountsCommandThreshold = commandThreshold; - } - } - - /** - * Checks for an old property path and moves it to a new path if it is present and the new path is not yet set. - * - * @param oldProperty The old property (create a temporary {@link Property} object with the path) - * @param newProperty The new property to move the value to - * @param reader The property reader - * @param configData Configuration data - * @param The type of the property - * @return True if a migration has been done, false otherwise - */ - protected static boolean moveProperty(Property oldProperty, - Property newProperty, - PropertyReader reader, - ConfigurationData configData) { - PropertyValue oldPropertyValue = oldProperty.determineValue(reader); - if (oldPropertyValue.isValidInResource()) { - if (reader.contains(newProperty.getPath())) { - logger.info("Detected deprecated property " + oldProperty.getPath()); - } else { - logger.info("Renaming " + oldProperty.getPath() + " to " + newProperty.getPath()); - configData.setValue(newProperty, oldPropertyValue.getValue()); - } - return true; - } - return false; - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/SettingsWarner.java b/src/main/java/fr/xephi/authme/settings/SettingsWarner.java deleted file mode 100644 index c63ffe71..00000000 --- a/src/main/java/fr/xephi/authme/settings/SettingsWarner.java +++ /dev/null @@ -1,90 +0,0 @@ -package fr.xephi.authme.settings; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.security.crypts.Argon2; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.properties.EmailSettings; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.settings.properties.SecuritySettings; - -import javax.inject.Inject; -import java.util.Optional; - -/** - * Logs warning messages in cases where the configured values suggest a misconfiguration. - *

- * Note that this class does not modify any settings and it is called after the settings have been fully loaded. - * For actual migrations (= verifications which trigger changes and a resave of the settings), - * see {@link SettingsMigrationService}. - */ -public class SettingsWarner { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(SettingsWarner.class); - - @Inject - private Settings settings; - - @Inject - private AuthMe authMe; - - @Inject - private BukkitService bukkitService; - - SettingsWarner() { - } - - /** - * Logs warning when necessary to notify the user about misconfigurations. - */ - public void logWarningsForMisconfigurations() { - // Force single session disabled - if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) { - logger.warning("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); - } - - // Use TLS property only affects port 25 - if (!settings.getProperty(EmailSettings.PORT25_USE_TLS) - && settings.getProperty(EmailSettings.SMTP_PORT) != 25) { - logger.warning("Note: You have set Email.useTls to false but this only affects mail over port 25"); - } - - // Output hint if sessions are enabled that the timeout must be positive - if (settings.getProperty(PluginSettings.SESSIONS_ENABLED) - && settings.getProperty(PluginSettings.SESSIONS_TIMEOUT) <= 0) { - logger.warning("Warning: Session timeout needs to be positive in order to work!"); - } - - // Warn if spigot.yml has settings.bungeecord set to true but config.yml has Hooks.bungeecord set to false - if (isTrue(bukkitService.isBungeeCordConfiguredForSpigot()) - && !settings.getProperty(HooksSettings.BUNGEECORD) && !settings.getProperty(HooksSettings.VELOCITY)) { - logger.warning("Note: Hooks.bungeecord is set to false but your server appears to be running in" - + " bungeecord mode (see your spigot.yml). In order to allow the datasource caching and the" - + " AuthMeBungee add-on to work properly you have to enable this option!"); - } - - if (!isTrue(bukkitService.isBungeeCordConfiguredForSpigot()) - && settings.getProperty(HooksSettings.BUNGEECORD)) { - logger.warning("Note: Hooks.bungeecord is set to true but your server appears to be running in" - + " non-bungeecord mode (see your spigot.yml). In order to prevent untrusted payload attack, " - + "BungeeCord hook will be automatically disabled!"); - } - - - // Check if argon2 library is present and can be loaded - if (settings.getProperty(SecuritySettings.PASSWORD_HASH).equals(HashAlgorithm.ARGON2) - && !Argon2.isLibraryLoaded()) { - logger.warning("WARNING!!! You use Argon2 Hash Algorithm method but we can't find the Argon2 " - + "library on your system! See https://github.com/AuthMe/AuthMeReloaded/wiki/Argon2-as-Password-Hash"); - authMe.stopOrUnload(); - } - } - - private static boolean isTrue(Optional value) { - return value.isPresent() && value.get(); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java deleted file mode 100644 index 47e9711d..00000000 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ /dev/null @@ -1,378 +0,0 @@ -package fr.xephi.authme.settings; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.service.PluginHookService; -import fr.xephi.authme.settings.properties.HooksSettings; -import fr.xephi.authme.settings.properties.RestrictionSettings; -import fr.xephi.authme.util.FileUtils; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.util.Locale; - -/** - * Manager for spawn points. It loads spawn definitions from AuthMe and third-party plugins - * and is responsible for returning the correct spawn point as per the settings. - *

- * The spawn priority setting defines from which sources and in which order the spawn point - * should be taken from. In AuthMe, we can distinguish between the regular spawn and a "first spawn", - * to which players will be teleported who have joined for the first time. - */ -public class SpawnLoader implements Reloadable { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(SpawnLoader.class); - - private final File authMeConfigurationFile; - private final Settings settings; - private final PluginHookService pluginHookService; - private FileConfiguration authMeConfiguration; - private String[] spawnPriority; - private Location essentialsSpawn; - private Location cmiSpawn; - - /** - * Constructor. - * - * @param pluginFolder The AuthMe data folder - * @param settings The setting instance - * @param pluginHookService The plugin hooks instance - */ - @Inject - SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService) { - File spawnFile = new File(pluginFolder, "spawn.yml"); - FileUtils.copyFileFromResource(spawnFile, "spawn.yml"); - this.authMeConfigurationFile = spawnFile; - this.settings = settings; - this.pluginHookService = pluginHookService; - reload(); - } - - /** - * (Re)loads the spawn file and relevant settings. - */ - @Override - public void reload() { - spawnPriority = settings.getProperty(RestrictionSettings.SPAWN_PRIORITY).split(","); - authMeConfiguration = YamlConfiguration.loadConfiguration(authMeConfigurationFile); - loadEssentialsSpawn(); - } - - /** - * Return the AuthMe spawn location. - * - * @return The location of the regular AuthMe spawn point - */ - public Location getSpawn() { - return getLocationFromConfiguration(authMeConfiguration, "spawn"); - } - - /** - * Set the AuthMe spawn point. - * - * @param location The location to use - * - * @return True upon success, false otherwise - */ - public boolean setSpawn(Location location) { - return setLocation("spawn", location); - } - - /** - * Return the AuthMe first spawn location. - * - * @return The location of the AuthMe spawn point for first timers - */ - public Location getFirstSpawn() { - return getLocationFromConfiguration(authMeConfiguration, "firstspawn"); - } - - /** - * Set the AuthMe first spawn location. - * - * @param location The location to use - * - * @return True upon success, false otherwise - */ - public boolean setFirstSpawn(Location location) { - return setLocation("firstspawn", location); - } - - /** - * Load the spawn point defined in EssentialsSpawn. - */ - public void loadEssentialsSpawn() { - // EssentialsSpawn cannot run without Essentials, so it's fine to get the Essentials data folder - File essentialsFolder = pluginHookService.getEssentialsDataFolder(); - if (essentialsFolder == null) { - return; - } - - File essentialsSpawnFile = new File(essentialsFolder, "spawn.yml"); - if (essentialsSpawnFile.exists()) { - essentialsSpawn = getLocationFromConfiguration( - YamlConfiguration.loadConfiguration(essentialsSpawnFile), "spawns.default"); - } else { - essentialsSpawn = null; - logger.info("Essentials spawn file not found: '" + essentialsSpawnFile.getAbsolutePath() + "'"); - } - } - - /** - * Unset the spawn point defined in EssentialsSpawn. - */ - public void unloadEssentialsSpawn() { - essentialsSpawn = null; - } - - /** - * Load the spawn point defined in CMI. - */ - public void loadCmiSpawn() { - File cmiFolder = pluginHookService.getCmiDataFolder(); - if (cmiFolder == null) { - return; - } - - File cmiConfig = new File(cmiFolder, "config.yml"); - if (cmiConfig.exists()) { - cmiSpawn = getLocationFromCmiConfiguration(YamlConfiguration.loadConfiguration(cmiConfig)); - } else { - cmiSpawn = null; - logger.info("CMI config file not found: '" + cmiConfig.getAbsolutePath() + "'"); - } - } - - /** - * Unset the spawn point defined in CMI. - */ - public void unloadCmiSpawn() { - cmiSpawn = null; - } - - /** - * Return the spawn location for the given player. The source of the spawn location varies - * depending on the spawn priority setting. - * - * @param player The player to retrieve the spawn point for - * - * @return The spawn location, or the default spawn location upon failure - * - * @see RestrictionSettings#SPAWN_PRIORITY - */ - public Location getSpawnLocation(Player player) { - if (player == null || player.getWorld() == null) { - return null; - } - - World world = player.getWorld(); - Location spawnLoc = null; - for (String priority : spawnPriority) { - switch (priority.toLowerCase(Locale.ROOT).trim()) { - case "default": - if (world.getSpawnLocation() != null) { - if (!isValidSpawnPoint(world.getSpawnLocation())) { - for (World spawnWorld : Bukkit.getWorlds()) { - if (isValidSpawnPoint(spawnWorld.getSpawnLocation())) { - world = spawnWorld; - break; - } - } - logger.warning("Seems like AuthMe is unable to find a proper spawn location. " - + "Set a location with the command '/authme setspawn'"); - } - spawnLoc = world.getSpawnLocation(); - } - break; - case "multiverse": - if (settings.getProperty(HooksSettings.MULTIVERSE)) { - spawnLoc = pluginHookService.getMultiverseSpawn(world); - } - break; - case "essentials": - spawnLoc = essentialsSpawn; - break; - case "cmi": - spawnLoc = cmiSpawn; - break; - case "authme": - spawnLoc = getSpawn(); - break; - default: - // ignore - } - if (spawnLoc != null) { - logger.debug("Spawn location determined as `{0}` for world `{1}`", spawnLoc, world.getName()); - return spawnLoc; - } - } - logger.debug("Fall back to default world spawn location. World: `{0}`", world.getName()); - - return world.getSpawnLocation(); // return default location - } - - /** - * Checks if a given location is a valid spawn point [!= (0,0,0)]. - * - * @param location The location to check - * - * @return True upon success, false otherwise - */ - private boolean isValidSpawnPoint(Location location) { - if (location.getX() == 0 && location.getY() == 0 && location.getZ() == 0) { - return false; - } - return true; - } - - /** - * Save the location under the given prefix. - * - * @param prefix The prefix to save the spawn under - * @param location The location to persist - * - * @return True upon success, false otherwise - */ - private boolean setLocation(String prefix, Location location) { - if (location != null && location.getWorld() != null) { - authMeConfiguration.set(prefix + ".world", location.getWorld().getName()); - authMeConfiguration.set(prefix + ".x", location.getX()); - authMeConfiguration.set(prefix + ".y", location.getY()); - authMeConfiguration.set(prefix + ".z", location.getZ()); - authMeConfiguration.set(prefix + ".yaw", location.getYaw()); - authMeConfiguration.set(prefix + ".pitch", location.getPitch()); - return saveAuthMeConfig(); - } - return false; - } - - private boolean saveAuthMeConfig() { - try { - authMeConfiguration.save(authMeConfigurationFile); - return true; - } catch (IOException e) { - logger.logException("Could not save spawn config (" + authMeConfigurationFile + ")", e); - } - return false; - } - - /** - * Return player's location if player is alive, or player's spawn location if dead. - * - * @param player player to retrieve - * - * @return location of the given player if alive, spawn location if dead. - */ - public Location getPlayerLocationOrSpawn(Player player) { - if (player.getHealth() <= 0.0) { - return getSpawnLocation(player); - } - return player.getLocation(); - } - - /** - * Build a {@link Location} object from the given path in the file configuration. - * - * @param configuration The file configuration to read from - * @param pathPrefix The path to get the spawn point from - * - * @return Location corresponding to the values in the path - */ - private static Location getLocationFromConfiguration(FileConfiguration configuration, String pathPrefix) { - if (containsAllSpawnFields(configuration, pathPrefix)) { - String prefix = pathPrefix + "."; - String worldName = configuration.getString(prefix + "world"); - World world = Bukkit.getWorld(worldName); - if (!StringUtils.isBlank(worldName) && world != null) { - return new Location(world, configuration.getDouble(prefix + "x"), - configuration.getDouble(prefix + "y"), configuration.getDouble(prefix + "z"), - getFloat(configuration, prefix + "yaw"), getFloat(configuration, prefix + "pitch")); - } - } - return null; - } - - /** - * Build a {@link Location} object based on the CMI configuration. - * - * @param configuration The CMI file configuration to read from - * - * @return Location corresponding to the values in the path - */ - private static Location getLocationFromCmiConfiguration(FileConfiguration configuration) { - final String pathPrefix = "Spawn.Main"; - if (isLocationCompleteInCmiConfig(configuration, pathPrefix)) { - String prefix = pathPrefix + "."; - String worldName = configuration.getString(prefix + "World"); - World world = Bukkit.getWorld(worldName); - if (!StringUtils.isBlank(worldName) && world != null) { - return new Location(world, configuration.getDouble(prefix + "X"), - configuration.getDouble(prefix + "Y"), configuration.getDouble(prefix + "Z"), - getFloat(configuration, prefix + "Yaw"), getFloat(configuration, prefix + "Pitch")); - } - } - return null; - } - - /** - * Return whether the file configuration contains all fields necessary to define a spawn - * under the given path. - * - * @param configuration The file configuration to use - * @param pathPrefix The path to verify - * - * @return True if all spawn fields are present, false otherwise - */ - private static boolean containsAllSpawnFields(FileConfiguration configuration, String pathPrefix) { - String[] fields = {"world", "x", "y", "z", "yaw", "pitch"}; - for (String field : fields) { - if (!configuration.contains(pathPrefix + "." + field)) { - return false; - } - } - return true; - } - - /** - * Return whether the CMI file configuration contains all spawn fields under the given path. - * - * @param cmiConfiguration The file configuration from CMI - * @param pathPrefix The path to verify - * - * @return True if all spawn fields are present, false otherwise - */ - private static boolean isLocationCompleteInCmiConfig(FileConfiguration cmiConfiguration, String pathPrefix) { - String[] fields = {"World", "X", "Y", "Z", "Yaw", "Pitch"}; - for (String field : fields) { - if (!cmiConfiguration.contains(pathPrefix + "." + field)) { - return false; - } - } - return true; - } - - /** - * Retrieve a property as a float from the given file configuration. - * - * @param configuration The file configuration to use - * @param path The path of the property to retrieve - * - * @return The float - */ - private static float getFloat(FileConfiguration configuration, String path) { - Object value = configuration.get(path); - // This behavior is consistent with FileConfiguration#getDouble - return (value instanceof Number) ? ((Number) value).floatValue() : 0; - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java b/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java deleted file mode 100644 index 5ac922b1..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -/** - * Command to be run. - */ -public class Command { - - /** The command to execute. */ - private String command; - /** The executor of the command. */ - private Executor executor = Executor.PLAYER; - /** Delay before executing the command (in ticks) */ - private long delay = 0; - - /** - * Default constructor (for bean mapping). - */ - public Command() { - } - - /** - * Creates a copy of this Command object, setting the given command text on the copy. - * - * @param command the command text to use in the copy - * @return copy of the source with the new command - */ - public Command copyWithCommand(String command) { - Command copy = new Command(); - setValuesToCopyWithNewCommand(copy, command); - return copy; - } - - protected void setValuesToCopyWithNewCommand(Command copy, String newCommand) { - copy.command = newCommand; - copy.executor = this.executor; - copy.delay = this.delay; - } - - public String getCommand() { - return command; - } - - public void setCommand(String command) { - this.command = command; - } - - public Executor getExecutor() { - return executor; - } - - public void setExecutor(Executor executor) { - this.executor = executor; - } - - public long getDelay() { - return delay; - } - - public void setDelay(long delay) { - this.delay = delay; - } - - @Override - public String toString() { - return command + " (" + executor + ")"; - } -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java deleted file mode 100644 index 29484ccd..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * Command configuration. - * - * @see CommandManager - */ -public class CommandConfig { - - private Map onJoin = new LinkedHashMap<>(); - private Map onLogin = new LinkedHashMap<>(); - private Map onSessionLogin = new LinkedHashMap<>(); - private Map onFirstLogin = new LinkedHashMap<>(); - private Map onRegister = new LinkedHashMap<>(); - private Map onUnregister = new LinkedHashMap<>(); - private Map onLogout = new LinkedHashMap<>(); - - public Map getOnJoin() { - return onJoin; - } - - public void setOnJoin(Map onJoin) { - this.onJoin = onJoin; - } - - public Map getOnLogin() { - return onLogin; - } - - public void setOnLogin(Map onLogin) { - this.onLogin = onLogin; - } - - public Map getOnSessionLogin() { - return onSessionLogin; - } - - public void setOnSessionLogin(Map onSessionLogin) { - this.onSessionLogin = onSessionLogin; - } - - public Map getOnFirstLogin() { - return onFirstLogin; - } - - public void setOnFirstLogin(Map onFirstLogin) { - this.onFirstLogin = onFirstLogin; - } - - public Map getOnRegister() { - return onRegister; - } - - public void setOnRegister(Map onRegister) { - this.onRegister = onRegister; - } - - public Map getOnUnregister() { - return onUnregister; - } - - public void setOnUnregister(Map onUnregister) { - this.onUnregister = onUnregister; - } - - public Map getOnLogout() { - return onLogout; - } - - public void setOnLogout(Map onLogout) { - this.onLogout = onLogout; - } -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java deleted file mode 100644 index 86f06aa8..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java +++ /dev/null @@ -1,192 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -import ch.jalu.configme.SettingsManager; -import ch.jalu.configme.SettingsManagerBuilder; -import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.GeoIpService; -import fr.xephi.authme.service.yaml.YamlFileResourceProvider; -import fr.xephi.authme.util.FileUtils; -import fr.xephi.authme.util.PlayerUtils; -import fr.xephi.authme.util.lazytags.Tag; -import fr.xephi.authme.util.lazytags.WrappedTagReplacer; -import org.bukkit.entity.Player; - -import javax.inject.Inject; -import java.io.File; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; - -import static fr.xephi.authme.util.lazytags.TagBuilder.createTag; - -/** - * Manages configurable commands to be run when various events occur. - */ -public class CommandManager implements Reloadable { - - private final File dataFolder; - private final BukkitService bukkitService; - private final GeoIpService geoIpService; - private final CommandMigrationService commandMigrationService; - private final List> availableTags = buildAvailableTags(); - - private WrappedTagReplacer onJoinCommands; - private WrappedTagReplacer onLoginCommands; - private WrappedTagReplacer onSessionLoginCommands; - private WrappedTagReplacer onFirstLoginCommands; - private WrappedTagReplacer onRegisterCommands; - private WrappedTagReplacer onUnregisterCommands; - private WrappedTagReplacer onLogoutCommands; - - @Inject - CommandManager(@DataFolder File dataFolder, BukkitService bukkitService, GeoIpService geoIpService, - CommandMigrationService commandMigrationService) { - this.dataFolder = dataFolder; - this.bukkitService = bukkitService; - this.geoIpService = geoIpService; - this.commandMigrationService = commandMigrationService; - reload(); - } - - /** - * Runs the configured commands for when a player has joined. - * - * @param player the joining player - */ - public void runCommandsOnJoin(Player player) { - executeCommands(player, onJoinCommands.getAdaptedItems(player)); - } - - /** - * Runs the configured commands for when a player has successfully registered. - * - * @param player the player who has registered - */ - public void runCommandsOnRegister(Player player) { - executeCommands(player, onRegisterCommands.getAdaptedItems(player)); - } - - /** - * Runs the configured commands for when a player has logged in successfully. - * - * @param player the player that logged in - * @param otherAccounts account names whose IP is the same as the player's - */ - public void runCommandsOnLogin(Player player, List otherAccounts) { - final int numberOfOtherAccounts = otherAccounts.size(); - executeCommands(player, onLoginCommands.getAdaptedItems(player), - cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts)); - } - - /** - * Runs the configured commands for when a player has logged in successfully due to session. - * - * @param player the player that logged in - */ - public void runCommandsOnSessionLogin(Player player) { - executeCommands(player, onSessionLoginCommands.getAdaptedItems(player)); - } - - /** - * Runs the configured commands for when a player logs in the first time. - * - * @param player the player that has logged in for the first time - * @param otherAccounts account names whose IP is the same as the player's - */ - public void runCommandsOnFirstLogin(Player player, List otherAccounts) { - final int numberOfOtherAccounts = otherAccounts.size(); - executeCommands(player, onFirstLoginCommands.getAdaptedItems(player), - cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts)); - } - - /** - * Runs the configured commands for when a player has been unregistered. - * - * @param player the player that has been unregistered - */ - public void runCommandsOnUnregister(Player player) { - executeCommands(player, onUnregisterCommands.getAdaptedItems(player)); - } - - /** - * Runs the configured commands for when a player logs out (by command or by quitting the server). - * - * @param player the player that is no longer logged in - */ - public void runCommandsOnLogout(Player player) { - executeCommands(player, onLogoutCommands.getAdaptedItems(player)); - } - - private void executeCommands(Player player, List commands) { - executeCommands(player, commands, c -> true); - } - - private void executeCommands(Player player, List commands, Predicate predicate) { - for (T cmd : commands) { - if (predicate.test(cmd)) { - long delay = cmd.getDelay(); - if (delay > 0) { - bukkitService.runTaskLater(player, () -> dispatchCommand(player, cmd), delay); - } else { - bukkitService.runTaskIfFolia(player, () -> dispatchCommand(player, cmd)); - } - } - } - } - - private void dispatchCommand(Player player, Command command) { - if (Executor.CONSOLE.equals(command.getExecutor())) { - bukkitService.dispatchConsoleCommand(command.getCommand()); - } else { - bukkitService.dispatchCommand(player, command.getCommand()); - } - } - - private static boolean shouldCommandBeRun(OnLoginCommand command, int numberOfOtherAccounts) { - return (!command.getIfNumberOfAccountsAtLeast().isPresent() - || command.getIfNumberOfAccountsAtLeast().get() <= numberOfOtherAccounts) - && (!command.getIfNumberOfAccountsLessThan().isPresent() - || command.getIfNumberOfAccountsLessThan().get() > numberOfOtherAccounts); - } - - @Override - public void reload() { - File file = new File(dataFolder, "commands.yml"); - FileUtils.copyFileFromResource(file, "commands.yml"); - - SettingsManager settingsManager = SettingsManagerBuilder - .withResource(YamlFileResourceProvider.loadFromFile(file)) - .configurationData(CommandSettingsHolder.class) - .migrationService(commandMigrationService) - .create(); - CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS); - onJoinCommands = newReplacer(commandConfig.getOnJoin()); - onLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnLogin()); - onFirstLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnFirstLogin()); - onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin()); - onRegisterCommands = newReplacer(commandConfig.getOnRegister()); - onUnregisterCommands = newReplacer(commandConfig.getOnUnregister()); - onLogoutCommands = newReplacer(commandConfig.getOnLogout()); - } - - private WrappedTagReplacer newReplacer(Map commands) { - return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand, - Command::copyWithCommand); - } - - private WrappedTagReplacer newOnLoginCmdReplacer(Map commands) { - return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand, - OnLoginCommand::copyWithCommand); - } - - private List> buildAvailableTags() { - return Arrays.asList( - createTag("%p", Player::getName), - createTag("%nick", Player::getDisplayName), - createTag("%ip", PlayerUtils::getPlayerIp), - createTag("%country", pl -> geoIpService.getCountryName(PlayerUtils.getPlayerIp(pl)))); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java deleted file mode 100644 index 0822616d..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.migration.MigrationService; -import ch.jalu.configme.resource.PropertyReader; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import fr.xephi.authme.settings.SettingsMigrationService; -import fr.xephi.authme.util.RandomStringUtils; - -import javax.inject.Inject; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * Migrates the commands from their old location, in config.yml, to the dedicated commands configuration file. - */ -class CommandMigrationService implements MigrationService { - - /** List of all properties in {@link CommandConfig}. */ - @VisibleForTesting - static final List COMMAND_CONFIG_PROPERTIES = ImmutableList.of( - "onJoin", "onLogin", "onSessionLogin", "onFirstLogin", "onRegister", "onUnregister", "onLogout"); - - @Inject - private SettingsMigrationService settingsMigrationService; - - CommandMigrationService() { - } - - @Override - public boolean checkAndMigrate(PropertyReader reader, ConfigurationData configurationData) { - final CommandConfig commandConfig = CommandSettingsHolder.COMMANDS.determineValue(reader).getValue(); - if (moveOtherAccountsConfig(commandConfig) || isAnyCommandMissing(reader)) { - configurationData.setValue(CommandSettingsHolder.COMMANDS, commandConfig); - return true; - } - return false; - } - - private boolean moveOtherAccountsConfig(CommandConfig commandConfig) { - if (settingsMigrationService.hasOldOtherAccountsCommand()) { - OnLoginCommand command = new OnLoginCommand(); - command.setCommand(replaceOldPlaceholdersWithNew(settingsMigrationService.getOldOtherAccountsCommand())); - command.setExecutor(Executor.CONSOLE); - command.setIfNumberOfAccountsAtLeast( - Optional.of(settingsMigrationService.getOldOtherAccountsCommandThreshold())); - - Map onLoginCommands = commandConfig.getOnLogin(); - onLoginCommands.put(RandomStringUtils.generate(10), command); - return true; - } - return false; - } - - private static String replaceOldPlaceholdersWithNew(String oldOtherAccountsCommand) { - return oldOtherAccountsCommand - .replace("%playername%", "%p") - .replace("%playerip%", "%ip"); - } - - private static boolean isAnyCommandMissing(PropertyReader reader) { - return COMMAND_CONFIG_PROPERTIES.stream().anyMatch(property -> reader.getObject(property) == null); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java deleted file mode 100644 index ab8e9849..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java +++ /dev/null @@ -1,77 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.configurationdata.CommentsConfiguration; -import ch.jalu.configme.properties.BeanProperty; -import ch.jalu.configme.properties.Property; - -/** - * Settings holder class for the commands.yml settings. - */ -public final class CommandSettingsHolder implements SettingsHolder { - - public static final Property COMMANDS = - new BeanProperty<>(CommandConfig.class, "", new CommandConfig()); - - private CommandSettingsHolder() { - } - - @Override - public void registerComments(CommentsConfiguration conf) { - String[] rootComments = { - "This configuration file allows you to execute commands on various events.", - "Supported placeholders in commands:", - " %p is replaced with the player name.", - " %nick is replaced with the player's nick name", - " %ip is replaced with the player's IP address", - " %country is replaced with the player's country", - "", - "For example, if you want to send a welcome message to a player who just registered:", - "onRegister:", - " welcome:", - " command: 'msg %p Welcome to the server!'", - " executor: CONSOLE", - "", - "This will make the console execute the msg command to the player.", - "Each command under an event has a name you can choose freely (e.g. 'welcome' as above),", - "after which a mandatory 'command' field defines the command to run,", - "and 'executor' defines who will run the command (either PLAYER or CONSOLE). Longer example:", - "onLogin:", - " welcome:", - " command: 'msg %p Welcome back!'", - " executor: PLAYER", - " broadcast:", - " command: 'broadcast %p has joined, welcome back!'", - " executor: CONSOLE", - "", - "You can also add delay to command. It will run after the specified ticks. Example:", - "onLogin:", - " rules:", - " command: 'rules'", - " executor: PLAYER", - " delay: 200", - "", - "Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, " - + "onUnregister", - "", - "For onLogin and onFirstLogin, you can use 'ifNumberOfAccountsLessThan' and 'ifNumberOfAccountsAtLeast'", - "to specify limits to how many accounts a player can have (matched by IP) for a command to be run:", - "onLogin:", - " warnOnManyAccounts:", - " command: 'say Uh oh! %p has many alt accounts!'", - " executor: CONSOLE", - " ifNumberOfAccountsAtLeast: 5" - }; - - conf.setComment("", rootComments); - conf.setComment("onFirstLogin", - "Commands to run for players logging in whose 'last login date' was empty"); - conf.setComment("onUnregister", - "Commands to run whenever a player is unregistered (by himself, or by an admin)"); - conf.setComment("onLogout", - "These commands are called whenever a logged in player uses /logout or quits.", - "The commands are not run if a player that was not logged in quits the server.", - "Note: if your server crashes, these commands won't be run, so don't rely on them to undo", - "'onLogin' commands that would be dangerous for non-logged in players to have!"); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java b/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java deleted file mode 100644 index c7043de2..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -/** - * The executor of the command. - */ -public enum Executor { - - /** The player of the event. */ - PLAYER, - - /** The console user. */ - CONSOLE - -} diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java b/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java deleted file mode 100644 index 13cc30fc..00000000 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java +++ /dev/null @@ -1,49 +0,0 @@ -package fr.xephi.authme.settings.commandconfig; - -import java.util.Optional; - -/** - * Configurable command for when a player logs in. - */ -public class OnLoginCommand extends Command { - - private Optional ifNumberOfAccountsAtLeast = Optional.empty(); - private Optional ifNumberOfAccountsLessThan = Optional.empty(); - - /** - * Default constructor (for bean mapping). - */ - public OnLoginCommand() { - } - - /** - * Creates a copy of this object, using the given command as new {@link Command#command command}. - * - * @param command the command text to use in the copy - * @return copy of the source with the new command - */ - @Override - public OnLoginCommand copyWithCommand(String command) { - OnLoginCommand copy = new OnLoginCommand(); - setValuesToCopyWithNewCommand(copy, command); - copy.ifNumberOfAccountsAtLeast = this.ifNumberOfAccountsAtLeast; - copy.ifNumberOfAccountsLessThan = this.ifNumberOfAccountsLessThan; - return copy; - } - - public Optional getIfNumberOfAccountsAtLeast() { - return ifNumberOfAccountsAtLeast; - } - - public void setIfNumberOfAccountsAtLeast(Optional ifNumberOfAccountsAtLeast) { - this.ifNumberOfAccountsAtLeast = ifNumberOfAccountsAtLeast; - } - - public Optional getIfNumberOfAccountsLessThan() { - return ifNumberOfAccountsLessThan; - } - - public void setIfNumberOfAccountsLessThan(Optional ifNumberOfAccountsLessThan) { - this.ifNumberOfAccountsLessThan = ifNumberOfAccountsLessThan; - } -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java b/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java deleted file mode 100644 index c3793485..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.configurationdata.ConfigurationData; -import ch.jalu.configme.configurationdata.ConfigurationDataBuilder; -import ch.jalu.configme.properties.Property; - -/** - * Utility class responsible for retrieving all {@link Property} fields from {@link SettingsHolder} classes. - */ -public final class AuthMeSettingsRetriever { - - private AuthMeSettingsRetriever() { - } - - /** - * Builds the configuration data for all property fields in AuthMe {@link SettingsHolder} classes. - * - * @return configuration data - */ - public static ConfigurationData buildConfigurationData() { - return ConfigurationDataBuilder.createConfiguration( - DatabaseSettings.class, PluginSettings.class, RestrictionSettings.class, - EmailSettings.class, HooksSettings.class, ProtectionSettings.class, - PurgeSettings.class, SecuritySettings.class, RegistrationSettings.class, - LimboSettings.class, BackupSettings.class, ConverterSettings.class); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java b/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java deleted file mode 100644 index 190c5b7d..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class BackupSettings implements SettingsHolder { - - @Comment("General configuration for backups: if false, no backups are possible") - public static final Property ENABLED = - newProperty("BackupSystem.ActivateBackup", false); - - @Comment("Create backup at every start of server") - public static final Property ON_SERVER_START = - newProperty("BackupSystem.OnServerStart", false); - - @Comment("Create backup at every stop of server") - public static final Property ON_SERVER_STOP = - newProperty("BackupSystem.OnServerStop", true); - - @Comment("Windows only: MySQL installation path") - public static final Property MYSQL_WINDOWS_PATH = - newProperty("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); - - private BackupSettings() { - } -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java deleted file mode 100644 index 2f677827..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.configurationdata.CommentsConfiguration; -import ch.jalu.configme.properties.Property; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class ConverterSettings implements SettingsHolder { - @Comment("CrazyLogin database file name") - public static final Property CRAZYLOGIN_FILE_NAME = - newProperty("Converter.CrazyLogin.fileName", "accounts.db"); - - @Comment("LoginSecurity: convert from SQLite; if false we use MySQL") - public static final Property LOGINSECURITY_USE_SQLITE = - newProperty("Converter.loginSecurity.useSqlite", true); - - @Comment("LoginSecurity MySQL: database host") - public static final Property LOGINSECURITY_MYSQL_HOST = - newProperty("Converter.loginSecurity.mySql.host", ""); - - @Comment("LoginSecurity MySQL: database name") - public static final Property LOGINSECURITY_MYSQL_DATABASE = - newProperty("Converter.loginSecurity.mySql.database", ""); - - @Comment("LoginSecurity MySQL: database user") - public static final Property LOGINSECURITY_MYSQL_USER = - newProperty("Converter.loginSecurity.mySql.user", ""); - - @Comment("LoginSecurity MySQL: password for database user") - public static final Property LOGINSECURITY_MYSQL_PASSWORD = - newProperty("Converter.loginSecurity.mySql.password", ""); - - private ConverterSettings() { - } - - @Override - public void registerComments(CommentsConfiguration conf) { - conf.setComment("Converter", - "Converter settings: see https://github.com/AuthMe/AuthMeReloaded/wiki/Converters"); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java deleted file mode 100644 index 6103183d..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java +++ /dev/null @@ -1,172 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.datasource.DataSourceType; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class DatabaseSettings implements SettingsHolder { - - @Comment({"What type of database do you want to use?", - "Valid values: H2, SQLITE, MARIADB, MYSQL, POSTGRESQL"}) - public static final Property BACKEND = - newProperty(DataSourceType.class, "DataSource.backend", DataSourceType.SQLITE); - - @Comment({"Enable the database caching system, should be disabled on bungeecord environments", - "or when a website integration is being used."}) - public static final Property USE_CACHING = - newProperty("DataSource.caching", true); - - @Comment("Should we try to use VirtualThreads(Java 21+) for database cache loader?") - public static final Property USE_VIRTUAL_THREADS = - newProperty("DataSource.useVirtualThreadsCache", false); - - @Comment("Database host address") - public static final Property MYSQL_HOST = - newProperty("DataSource.mySQLHost", "127.0.0.1"); - - @Comment("Database port") - public static final Property MYSQL_PORT = - newProperty("DataSource.mySQLPort", "3306"); - - @Comment({"Replacement of Mysql's useSsl (for MariaDB only).", - "- disable: No SSL", - "- trust: Trust blindly (no validation)", - "- verify_ca: Encryption, certificates validation, BUT no hostname verification", - "- verify_full: Encryption, certificate validation and hostname validation", - "Read more: https://bit.ly/mariadb-sslmode"}) - public static final Property MARIADB_SSL_MODE = - newProperty("DataSource.MariaDbSslMode", "disabled"); - - @Comment({"Connect to MySQL database over SSL", - "If you're using MariaDB, use sslMode instead"}) - public static final Property MYSQL_USE_SSL = - newProperty("DataSource.mySQLUseSSL", true); - - @Comment({"Verification of server's certificate.", - "We would not recommend to set this option to false.", - "Set this option to false at your own risk if and only if you know what you're doing"}) - public static final Property MYSQL_CHECK_SERVER_CERTIFICATE = - newProperty( "DataSource.mySQLCheckServerCertificate", true); - - @Comment({"Authorize client to retrieve RSA server public key.", - "Advanced option, ignore if you don't know what it means.", - "If you are using MariaDB, use MariaDbSslMode instead."}) - public static final Property MYSQL_ALLOW_PUBLIC_KEY_RETRIEVAL = - newProperty( "DataSource.mySQLAllowPublicKeyRetrieval", true); - - @Comment("Username to connect to the MySQL database") - public static final Property MYSQL_USERNAME = - newProperty("DataSource.mySQLUsername", "authme"); - - @Comment("Password to connect to the MySQL database") - public static final Property MYSQL_PASSWORD = - newProperty("DataSource.mySQLPassword", "12345"); - - @Comment("Database Name, use with converters or as SQLITE database name") - public static final Property MYSQL_DATABASE = - newProperty("DataSource.mySQLDatabase", "authme"); - - @Comment("Table of the database") - public static final Property MYSQL_TABLE = - newProperty("DataSource.mySQLTablename", "authme"); - - @Comment("Column of IDs to sort data") - public static final Property MYSQL_COL_ID = - newProperty("DataSource.mySQLColumnId", "id"); - - @Comment("Column for storing or checking players nickname") - public static final Property MYSQL_COL_NAME = - newProperty("DataSource.mySQLColumnName", "username"); - - @Comment("Column for storing or checking players RealName") - public static final Property MYSQL_COL_REALNAME = - newProperty("DataSource.mySQLRealName", "realname"); - - @Comment("Column for storing players passwords") - public static final Property MYSQL_COL_PASSWORD = - newProperty("DataSource.mySQLColumnPassword", "password"); - - @Comment("Column for storing players passwords salts") - public static final Property MYSQL_COL_SALT = - newProperty("DataSource.mySQLColumnSalt", ""); - - @Comment("Column for storing players emails") - public static final Property MYSQL_COL_EMAIL = - newProperty("DataSource.mySQLColumnEmail", "email"); - - @Comment("Column for storing if a player is logged in or not") - public static final Property MYSQL_COL_ISLOGGED = - newProperty("DataSource.mySQLColumnLogged", "isLogged"); - - @Comment("Column for storing if a player has a valid session or not") - public static final Property MYSQL_COL_HASSESSION = - newProperty("DataSource.mySQLColumnHasSession", "hasSession"); - - @Comment("Column for storing a player's TOTP key (for two-factor authentication)") - public static final Property MYSQL_COL_TOTP_KEY = - newProperty("DataSource.mySQLtotpKey", "totp"); - - @Comment("Column for storing the player's last IP") - public static final Property MYSQL_COL_LAST_IP = - newProperty("DataSource.mySQLColumnIp", "ip"); - - @Comment("Column for storing players lastlogins") - public static final Property MYSQL_COL_LASTLOGIN = - newProperty("DataSource.mySQLColumnLastLogin", "lastlogin"); - - @Comment("Column storing the registration date") - public static final Property MYSQL_COL_REGISTER_DATE = - newProperty("DataSource.mySQLColumnRegisterDate", "regdate"); - - @Comment("Column for storing the IP address at the time of registration") - public static final Property MYSQL_COL_REGISTER_IP = - newProperty("DataSource.mySQLColumnRegisterIp", "regip"); - - @Comment("Column for storing player LastLocation - X") - public static final Property MYSQL_COL_LASTLOC_X = - newProperty("DataSource.mySQLlastlocX", "x"); - - @Comment("Column for storing player LastLocation - Y") - public static final Property MYSQL_COL_LASTLOC_Y = - newProperty("DataSource.mySQLlastlocY", "y"); - - @Comment("Column for storing player LastLocation - Z") - public static final Property MYSQL_COL_LASTLOC_Z = - newProperty("DataSource.mySQLlastlocZ", "z"); - - @Comment("Column for storing player LastLocation - World Name") - public static final Property MYSQL_COL_LASTLOC_WORLD = - newProperty("DataSource.mySQLlastlocWorld", "world"); - - @Comment("Column for storing player LastLocation - Yaw") - public static final Property MYSQL_COL_LASTLOC_YAW = - newProperty("DataSource.mySQLlastlocYaw", "yaw"); - - @Comment("Column for storing player LastLocation - Pitch") - public static final Property MYSQL_COL_LASTLOC_PITCH = - newProperty("DataSource.mySQLlastlocPitch", "pitch"); - - @Comment("Column for storing players uuids (optional)") - public static final Property MYSQL_COL_PLAYER_UUID = - newProperty( "DataSource.mySQLPlayerUUID", "" ); - - @Comment("Column for storing players groups") - public static final Property MYSQL_COL_GROUP = - newProperty("ExternalBoardOptions.mySQLColumnGroup", ""); - - @Comment("Overrides the size of the DB Connection Pool, default = 10") - public static final Property MYSQL_POOL_SIZE = - newProperty("DataSource.poolSize", 10); - - @Comment({"The maximum lifetime of a connection in the pool, default = 1800 seconds", - "You should set this at least 30 seconds less than mysql server wait_timeout"}) - public static final Property MYSQL_CONNECTION_MAX_LIFETIME = - newProperty("DataSource.maxLifetime", 1800); - - private DatabaseSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java b/src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java deleted file mode 100644 index a0cc03e2..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java +++ /dev/null @@ -1,76 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class EmailSettings implements SettingsHolder { - - @Comment("Email SMTP server host") - public static final Property SMTP_HOST = - newProperty("Email.mailSMTP", "smtp.163.com"); - - @Comment("Email SMTP server port") - public static final Property SMTP_PORT = - newProperty("Email.mailPort", 465); - - @Comment("Only affects port 25: enable TLS/STARTTLS?") - public static final Property PORT25_USE_TLS = - newProperty("Email.useTls", true); - - @Comment("Email account which sends the mails") - public static final Property MAIL_ACCOUNT = - newProperty("Email.mailAccount", ""); - - @Comment("Email account password") - public static final Property MAIL_PASSWORD = - newProperty("Email.mailPassword", ""); - - @Comment("Email address, fill when mailAccount is not the email address of the account") - public static final Property MAIL_ADDRESS = - newProperty("Email.mailAddress", ""); - - @Comment("Custom sender name, replacing the mailAccount name in the email") - public static final Property MAIL_SENDER_NAME = - newProperty("Email.mailSenderName", ""); - - @Comment("Recovery password length") - public static final Property RECOVERY_PASSWORD_LENGTH = - newProperty("Email.RecoveryPasswordLength", 12); - - @Comment("Mail Subject") - public static final Property RECOVERY_MAIL_SUBJECT = - newProperty("Email.mailSubject", "Your new AuthMe password"); - - @Comment("Like maxRegPerIP but with email") - public static final Property MAX_REG_PER_EMAIL = - newProperty("Email.maxRegPerEmail", 1); - - @Comment("Recall players to add an email?") - public static final Property RECALL_PLAYERS = - newProperty("Email.recallPlayers", false); - - @Comment("Delay in minute for the recall scheduler") - public static final Property DELAY_RECALL = - newProperty("Email.delayRecall", 5); - - @Comment("Send the new password drawn in an image?") - public static final Property PASSWORD_AS_IMAGE = - newProperty("Email.generateImage", false); - - @Comment("The OAuth2 token") - public static final Property OAUTH2_TOKEN = - newProperty("Email.emailOauth2Token", ""); - @Comment("Email notifications when the server shuts down") - public static final Property SHUTDOWN_MAIL = - newProperty("Email.shutDownEmail", false); - @Comment("Email notification address when the server is shut down") - public static final Property SHUTDOWN_MAIL_ADDRESS = - newProperty("Email.shutDownEmailAddress", "your@mail.com"); - - private EmailSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java deleted file mode 100644 index 08c91c6a..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java +++ /dev/null @@ -1,101 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import java.util.List; - -import static ch.jalu.configme.properties.PropertyInitializer.newListProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class HooksSettings implements SettingsHolder { - - @Comment("Do we need to hook with multiverse for spawn checking?") - public static final Property MULTIVERSE = - newProperty("Hooks.multiverse", true); - - @Comment("Do we need to hook with BungeeCord?") - public static final Property BUNGEECORD = - newProperty("Hooks.bungeecord", false); - @Comment("Do we need to hook with Velocity?") - public static final Property VELOCITY = - newProperty("Hooks.velocity", false); - - @Comment({"How many ticks should we wait before sending login info to proxy?", - "Change this to higher if your player has high ping.", - "See: https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/"}) - public static final Property PROXY_SEND_DELAY = - newProperty("Hooks.proxySendDelay", 10L); - - @Comment({"Hook into floodgate.", - "This must be true if you want to use other bedrock features." - }) - public static final Property HOOK_FLOODGATE_PLAYER = - newProperty("Hooks.floodgate", false); - - @Comment("Allow bedrock players join without check isValidName?") - public static final Property IGNORE_BEDROCK_NAME_CHECK = - newProperty("Hooks.ignoreBedrockNameCheck", true); - - - @Comment("Send player to this BungeeCord server after register/login") - public static final Property BUNGEECORD_SERVER = - newProperty("Hooks.sendPlayerTo", ""); - - @Comment("Do we need to disable Essentials SocialSpy on join?") - public static final Property DISABLE_SOCIAL_SPY = - newProperty("Hooks.disableSocialSpy", false); - - @Comment("Do we need to force /motd Essentials command on join?") - public static final Property USE_ESSENTIALS_MOTD = - newProperty("Hooks.useEssentialsMotd", false); - - @Comment({ - "-1 means disabled. If you want that only activated players", - "can log into your server, you can set here the group number", - "of unactivated users, needed for some forum/CMS support"}) - public static final Property NON_ACTIVATED_USERS_GROUP = - newProperty("ExternalBoardOptions.nonActivedUserGroup", -1); - - @Comment("Other MySQL columns where we need to put the username (case-sensitive)") - public static final Property> MYSQL_OTHER_USERNAME_COLS = - newListProperty("ExternalBoardOptions.mySQLOtherUsernameColumns"); - - @Comment("How much log2 rounds needed in BCrypt (do not change if you do not know what it does)") - public static final Property BCRYPT_LOG2_ROUND = - newProperty("ExternalBoardOptions.bCryptLog2Round", 12); - - @Comment("phpBB table prefix defined during the phpBB installation process") - public static final Property PHPBB_TABLE_PREFIX = - newProperty("ExternalBoardOptions.phpbbTablePrefix", "phpbb_"); - - @Comment("phpBB activated group ID; 2 is the default registered group defined by phpBB") - public static final Property PHPBB_ACTIVATED_GROUP_ID = - newProperty("ExternalBoardOptions.phpbbActivatedGroupId", 2); - - @Comment("IP Board table prefix defined during the IP Board installation process") - public static final Property IPB_TABLE_PREFIX = - newProperty("ExternalBoardOptions.IPBTablePrefix", "ipb_"); - - @Comment("IP Board default group ID; 3 is the default registered group defined by IP Board") - public static final Property IPB_ACTIVATED_GROUP_ID = - newProperty("ExternalBoardOptions.IPBActivatedGroupId", 3); - - @Comment("Xenforo table prefix defined during the Xenforo installation process") - public static final Property XF_TABLE_PREFIX = - newProperty("ExternalBoardOptions.XFTablePrefix", "xf_"); - - @Comment("XenForo default group ID; 2 is the default registered group defined by Xenforo") - public static final Property XF_ACTIVATED_GROUP_ID = - newProperty("ExternalBoardOptions.XFActivatedGroupId", 2); - - @Comment("Wordpress prefix defined during WordPress installation") - public static final Property WORDPRESS_TABLE_PREFIX = - newProperty("ExternalBoardOptions.wordpressTablePrefix", "wp_"); - - - private HooksSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/LimboSettings.java b/src/main/java/fr/xephi/authme/settings/properties/LimboSettings.java deleted file mode 100644 index 309b6923..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/LimboSettings.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.configurationdata.CommentsConfiguration; -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.data.limbo.AllowFlightRestoreType; -import fr.xephi.authme.data.limbo.WalkFlySpeedRestoreType; -import fr.xephi.authme.data.limbo.persistence.LimboPersistenceType; -import fr.xephi.authme.data.limbo.persistence.SegmentSize; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -/** - * Settings for the LimboPlayer feature. - */ -public final class LimboSettings implements SettingsHolder { - - @Comment({ - "Besides storing the data in memory, you can define if/how the data should be persisted", - "on disk. This is useful in case of a server crash, so next time the server starts we can", - "properly restore things like OP status, ability to fly, and walk/fly speed.", - "DISABLED: no disk storage,", - "INDIVIDUAL_FILES: each player data in its own file,", - "DISTRIBUTED_FILES: distributes players into different files based on their UUID, see below" - }) - public static final Property LIMBO_PERSISTENCE_TYPE = - newProperty(LimboPersistenceType.class, "limbo.persistence.type", LimboPersistenceType.INDIVIDUAL_FILES); - - @Comment({ - "This setting only affects DISTRIBUTED_FILES persistence. The distributed file", - "persistence attempts to reduce the number of files by distributing players into various", - "buckets based on their UUID. This setting defines into how many files the players should", - "be distributed. Possible values: ONE, FOUR, EIGHT, SIXTEEN, THIRTY_TWO, SIXTY_FOUR,", - "ONE_TWENTY for 128, TWO_FIFTY for 256.", - "For example, if you expect 100 non-logged in players, setting to SIXTEEN will average", - "6.25 players per file (100 / 16).", - "Note: if you change this setting all data will be migrated. If you have a lot of data,", - "change this setting only on server restart, not with /authme reload." - }) - public static final Property DISTRIBUTION_SIZE = - newProperty(SegmentSize.class, "limbo.persistence.distributionSize", SegmentSize.SIXTEEN); - - @Comment({ - "Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE, NOTHING.", - "RESTORE sets back the old property from the player. NOTHING will prevent AuthMe", - "from modifying the 'allow flight' property on the player." - }) - public static final Property RESTORE_ALLOW_FLIGHT = - newProperty(AllowFlightRestoreType.class, "limbo.restoreAllowFlight", AllowFlightRestoreType.RESTORE); - - @Comment({ - "Restore fly speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.", - "RESTORE: restore the speed the player had;", - "DEFAULT: always set to default speed;", - "MAX_RESTORE: take the maximum of the player's current speed and the previous one", - "RESTORE_NO_ZERO: Like 'restore' but sets speed to default if the player's speed was 0" - }) - public static final Property RESTORE_FLY_SPEED = - newProperty(WalkFlySpeedRestoreType.class, "limbo.restoreFlySpeed", WalkFlySpeedRestoreType.RESTORE_NO_ZERO); - - @Comment({ - "Restore walk speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.", - "See above for a description of the values." - }) - public static final Property RESTORE_WALK_SPEED = - newProperty(WalkFlySpeedRestoreType.class, "limbo.restoreWalkSpeed", WalkFlySpeedRestoreType.RESTORE_NO_ZERO); - - private LimboSettings() { - } - - @Override - public void registerComments(CommentsConfiguration conf) { - String[] limboExplanation = { - "Before a user logs in, various properties are temporarily removed from the player,", - "such as OP status, ability to fly, and walk/fly speed.", - "Once the user is logged in, we add back the properties we previously saved.", - "In this section, you may define how these properties should be handled.", - "Read more at https://github.com/AuthMe/AuthMeReloaded/wiki/Limbo-players" - }; - conf.setComment("limbo", limboExplanation); - } -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java deleted file mode 100644 index 221496b3..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ /dev/null @@ -1,122 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.output.LogLevel; - -import java.util.Set; - -import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class PluginSettings implements SettingsHolder { - @Comment({ - "Should we execute /help command when unregistered players press Shift+F?", - "This keeps compatibility with some menu plugins", - "If you are using TrMenu, don't enable this because TrMenu already implemented this." - }) - public static final Property MENU_UNREGISTER_COMPATIBILITY = - newProperty("3rdPartyFeature.compatibility.menuPlugins", false); - - @Comment({ - "Send i18n messages to player based on their client settings, this option will override `settings.messagesLanguage`", - "(Requires Protocollib or Packetevents)", - "This will not affect language of AuthMe help command." - }) - public static final Property I18N_MESSAGES = - newProperty("3rdPartyFeature.features.i18nMessages.enabled", false); - - @Comment({"Redirect locale code to certain AuthMe language code as you want", - "Minecraft locale list: https://minecraft.wiki/w/Language", - "AuthMe language code: https://github.com/HaHaWTH/AuthMeReReloaded/blob/master/docs/translations.md", - "For example, if you want to show Russian messages to player using language Tatar(tt_ru),", - "and show Chinese Simplified messages to player using language Classical Chinese(lzh), then:", - "locale-code-redirect:", - "- 'tt_ru:ru'", - "- 'lzh:zhcn'"}) - public static final Property> I18N_CODE_REDIRECT = - newLowercaseStringSetProperty("3rdPartyFeature.features.i18nMessages.locale-code-redirect", - "tt_ru:ru", "lzh:zhcn"); - - @Comment({ - "Do you want to enable the session feature?", - "If enabled, when a player authenticates successfully,", - "his IP and his nickname is saved.", - "The next time the player joins the server, if his IP", - "is the same as last time and the timeout hasn't", - "expired, he will not need to authenticate." - }) - public static final Property SESSIONS_ENABLED = - newProperty("settings.sessions.enabled", true); - - @Comment({ - "After how many minutes should a session expire?", - "A player's session ends after the timeout or if his IP has changed" - }) - public static final Property SESSIONS_TIMEOUT = - newProperty("settings.sessions.timeout", 43200); - - @Comment({ - "Message language, available languages:", - "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md", - "Example: zhcn, en" - }) - public static final Property MESSAGES_LANGUAGE = - newProperty("settings.messagesLanguage", "en"); - - @Comment({ - "Enables switching a player to defined permission groups before they log in.", - "See below for a detailed explanation." - }) - public static final Property ENABLE_PERMISSION_CHECK = - newProperty("GroupOptions.enablePermissionCheck", false); - - @Comment({ - "This is a very important option: if a registered player joins the server", - "AuthMe will switch him to unLoggedInGroup. This should prevent all major exploits.", - "You can set up your permission plugin with this special group to have no permissions,", - "or only permission to chat (or permission to send private messages etc.).", - "The better way is to set up this group with few permissions, so if a player", - "tries to exploit an account they can do only what you've defined for the group.", - "After login, the player will be moved to his correct permissions group!", - "Please note that the group name is case-sensitive, so 'admin' is different from 'Admin'", - "Otherwise your group will be wiped and the player will join in the default group []!", - "Example: registeredPlayerGroup: 'NotLogged'" - }) - public static final Property REGISTERED_GROUP = - newProperty("GroupOptions.registeredPlayerGroup", ""); - - @Comment({ - "Similar to above, unregistered players can be set to the following", - "permissions group" - }) - public static final Property UNREGISTERED_GROUP = - newProperty("GroupOptions.unregisteredPlayerGroup", ""); - - @Comment("Forces authme to hook into Vault instead of a specific permission handler system.") - public static final Property FORCE_VAULT_HOOK = - newProperty("settings.forceVaultHook", false); - - @Comment({ - "Log level: INFO, FINE, DEBUG. Use INFO for general messages,", - "FINE for some additional detailed ones (like password failed),", - "and DEBUG for debugging" - }) - public static final Property LOG_LEVEL = - newProperty(LogLevel.class, "settings.logLevel", LogLevel.FINE); - - @Comment({ - "By default we schedule async tasks when talking to the database. If you want", - "typical communication with the database to happen synchronously, set this to false" - }) - public static final Property USE_ASYNC_TASKS = - newProperty("settings.useAsyncTasks", true); - - @Comment("The name of the server, used in some placeholders.") - public static final Property SERVER_NAME = newProperty("settings.serverName", "Your Minecraft Server"); - - private PluginSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java deleted file mode 100644 index 7becd390..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import java.util.List; - -import static ch.jalu.configme.properties.PropertyInitializer.newListProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - - -public final class ProtectionSettings implements SettingsHolder { - - @Comment("Enable some servers protection (country based login, antibot)") - public static final Property ENABLE_PROTECTION = - newProperty("Protection.enableProtection", false); - - @Comment("Apply the protection also to registered usernames") - public static final Property ENABLE_PROTECTION_REGISTERED = - newProperty("Protection.enableProtectionRegistered", false); - - @Comment({ - "Countries allowed to join the server and register. For country codes, see", - "https://dev.maxmind.com/geoip/legacy/codes/iso3166/", - "Use \"LOCALHOST\" for local addresses.", - "PLEASE USE QUOTES!"}) - public static final Property> COUNTRIES_WHITELIST = - newListProperty("Protection.countries", "LOCALHOST"); - - @Comment({ - "Countries not allowed to join the server and register", - "PLEASE USE QUOTES!"}) - public static final Property> COUNTRIES_BLACKLIST = - newListProperty("Protection.countriesBlacklist", "A1"); - - @Comment("Do we need to enable automatic antibot system?") - public static final Property ENABLE_ANTIBOT = - newProperty("Protection.enableAntiBot", true); - - @Comment("The interval in seconds") - public static final Property ANTIBOT_INTERVAL = - newProperty("Protection.antiBotInterval", 5); - - @Comment({ - "Max number of players allowed to login in the interval", - "before the AntiBot system is enabled automatically"}) - public static final Property ANTIBOT_SENSIBILITY = - newProperty("Protection.antiBotSensibility", 10); - - @Comment("Duration in minutes of the antibot automatic system") - public static final Property ANTIBOT_DURATION = - newProperty("Protection.antiBotDuration", 10); - - @Comment("Delay in seconds before the antibot activation") - public static final Property ANTIBOT_DELAY = - newProperty("Protection.antiBotDelay", 60); - - @Comment("Kicks the player that issued a command before the defined time after the join process") - public static final Property QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS = - newProperty("Protection.quickCommands.denyCommandsBeforeMilliseconds", 1000); - - private ProtectionSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java deleted file mode 100644 index 0064fd40..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class PurgeSettings implements SettingsHolder { - - @Comment("If enabled, AuthMe automatically purges old, unused accounts") - public static final Property USE_AUTO_PURGE = - newProperty("Purge.useAutoPurge", false); - - @Comment("Number of days after which an account should be purged") - public static final Property DAYS_BEFORE_REMOVE_PLAYER = - newProperty("Purge.daysBeforeRemovePlayer", 60); - - @Comment("Do we need to remove the player.dat file during purge process?") - public static final Property REMOVE_PLAYER_DAT = - newProperty("Purge.removePlayerDat", false); - - @Comment("Do we need to remove the Essentials/userdata/player.yml file during purge process?") - public static final Property REMOVE_ESSENTIALS_FILES = - newProperty("Purge.removeEssentialsFile", false); - - @Comment("World in which the players.dat are stored") - public static final Property DEFAULT_WORLD = - newProperty("Purge.defaultWorld", "world"); - - @Comment("Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?") - public static final Property REMOVE_LIMITED_CREATIVE_INVENTORIES = - newProperty("Purge.removeLimitedCreativesInventories", false); - - @Comment("Do we need to remove the AntiXRayData/PlayerData/player file during purge process?") - public static final Property REMOVE_ANTI_XRAY_FILE = - newProperty("Purge.removeAntiXRayFile", false); - - @Comment("Do we need to remove permissions?") - public static final Property REMOVE_PERMISSIONS = - newProperty("Purge.removePermissions", false); - - private PurgeSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java deleted file mode 100644 index b15132d5..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java +++ /dev/null @@ -1,108 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.process.register.RegisterSecondaryArgument; -import fr.xephi.authme.process.register.RegistrationType; - -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class RegistrationSettings implements SettingsHolder { - - @Comment("Enable registration on the server?") - public static final Property IS_ENABLED = - newProperty("settings.registration.enabled", true); - - @Comment({ - "Send every X seconds a message to a player to", - "remind him that he has to login/register"}) - public static final Property MESSAGE_INTERVAL = - newProperty("settings.registration.messageInterval", 5); - - @Comment({ - "Only registered and logged in players can play.", - "See restrictions for exceptions"}) - public static final Property FORCE = - newProperty("settings.registration.force", true); - - @Comment({ - "Type of registration: PASSWORD or EMAIL", - "PASSWORD = account is registered with a password supplied by the user;", - "EMAIL = password is generated and sent to the email provided by the user.", - "More info at https://github.com/AuthMe/AuthMeReloaded/wiki/Registration" - }) - public static final Property REGISTRATION_TYPE = - newProperty(RegistrationType.class, "settings.registration.type", RegistrationType.PASSWORD); - - @Comment({ - "Second argument the /register command should take: ", - "NONE = no 2nd argument", - "CONFIRMATION = must repeat first argument (pass or email)", - "EMAIL_OPTIONAL = for password register: 2nd argument can be empty or have email address", - "EMAIL_MANDATORY = for password register: 2nd argument MUST be an email address" - }) - public static final Property REGISTER_SECOND_ARGUMENT = - newProperty(RegisterSecondaryArgument.class, "settings.registration.secondArg", - RegisterSecondaryArgument.CONFIRMATION); - - @Comment({ - "Should we unregister the player when he didn't verify the email?", - "This only works if you enabled email registration."}) - public static final Property UNREGISTER_ON_EMAIL_VERIFICATION_FAILURE = - newProperty("settings.registration.email.unregisterOnEmailVerificationFailure", false); - - @Comment({"How many minutes should we wait before unregister the player", - "when he didn't verify the email?"}) - public static final Property UNREGISTER_AFTER_MINUTES = - newProperty("settings.registration.email.unregisterAfterMinutes", 10L); - @Comment({ - "Do we force kick a player after a successful registration?", - "Do not use with login feature below"}) - public static final Property FORCE_KICK_AFTER_REGISTER = - newProperty("settings.registration.forceKickAfterRegister", false); - - @Comment("Does AuthMe need to enforce a /login after a successful registration?") - public static final Property FORCE_LOGIN_AFTER_REGISTER = - newProperty("settings.registration.forceLoginAfterRegister", false); - @Comment("Should we delay the join message and display it once the player has logged in?") - public static final Property DELAY_JOIN_MESSAGE = - newProperty("settings.delayJoinMessage", true); - - @Comment({ - "The custom join message that will be sent after a successful login,", - "keep empty to use the original one.", - "Available variables:", - "{PLAYERNAME}: the player name (no colors)", - "{DISPLAYNAME}: the player display name (with colors)", - "{DISPLAYNAMENOCOLOR}: the player display name (without colors)"}) - public static final Property CUSTOM_JOIN_MESSAGE = - newProperty("settings.customJoinMessage", ""); - - @Comment("Should we remove the leave messages of unlogged users?") - public static final Property REMOVE_UNLOGGED_LEAVE_MESSAGE = - newProperty("settings.removeUnloggedLeaveMessage", true); - - @Comment("Should we remove join messages altogether?") - public static final Property REMOVE_JOIN_MESSAGE = - newProperty("settings.removeJoinMessage", true); - - @Comment("Should we remove leave messages altogether?") - public static final Property REMOVE_LEAVE_MESSAGE = - newProperty("settings.removeLeaveMessage", true); - - @Comment("Do we need to add potion effect Blinding before login/register?") - public static final Property APPLY_BLIND_EFFECT = - newProperty("settings.applyBlindEffect", false); - - @Comment({ - "Do we need to prevent people to login with another case?", - "If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI"}) - public static final Property PREVENT_OTHER_CASE = - newProperty("settings.preventOtherCase", true); - - - private RegistrationSettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java deleted file mode 100644 index 1fc8341f..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ /dev/null @@ -1,217 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; - -import java.util.List; -import java.util.Set; - -import static ch.jalu.configme.properties.PropertyInitializer.newListProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class RestrictionSettings implements SettingsHolder { - - @Comment({ - "Can not authenticated players chat?", - "Keep in mind that this feature also blocks all commands not", - "listed in the list below."}) - public static final Property ALLOW_CHAT = - newProperty("settings.restrictions.allowChat", false); - - @Comment("Hide the chat log from players who are not authenticated?") - public static final Property HIDE_CHAT = - newProperty("settings.restrictions.hideChat", false); - - @Comment("Allowed commands for unauthenticated players") - public static final Property> ALLOW_COMMANDS = - newLowercaseStringSetProperty("settings.restrictions.allowCommands", - "/login", "/log", "/l", "/register", "/reg", "/email", "/captcha", "/2fa", "/totp"); - - @Comment({ - "Max number of allowed registrations per IP", - "The value 0 means an unlimited number of registrations!"}) - public static final Property MAX_REGISTRATION_PER_IP = - newProperty("settings.restrictions.maxRegPerIp", 3); - - @Comment("Minimum allowed username length") - public static final Property MIN_NICKNAME_LENGTH = - newProperty("settings.restrictions.minNicknameLength", 3); - - @Comment("Maximum allowed username length") - public static final Property MAX_NICKNAME_LENGTH = - newProperty("settings.restrictions.maxNicknameLength", 16); - - @Comment({ - "When this setting is enabled, online players can't be kicked out", - "due to \"Logged in from another Location\"", - "This setting will prevent potential security exploits."}) - public static final Property FORCE_SINGLE_SESSION = - newProperty("settings.restrictions.ForceSingleSession", true); - - @Comment({ - "If enabled, every player that spawn in one of the world listed in", - "\"ForceSpawnLocOnJoin.worlds\" will be teleported to the spawnpoint after successful", - "authentication. The quit location of the player will be overwritten.", - "This is different from \"teleportUnAuthedToSpawn\" that teleport player", - "to the spawnpoint on join."}) - public static final Property FORCE_SPAWN_LOCATION_AFTER_LOGIN = - newProperty("settings.restrictions.ForceSpawnLocOnJoin.enabled", false); - - @Comment({ - "WorldNames where we need to force the spawn location", - "Case-sensitive!"}) - public static final Property> FORCE_SPAWN_ON_WORLDS = - newListProperty("settings.restrictions.ForceSpawnLocOnJoin.worlds", - "world", "world_nether", "world_the_end"); - - @Comment("This option will save the quit location of the players.") - public static final Property SAVE_QUIT_LOCATION = - newProperty("settings.restrictions.SaveQuitLocation", false); - - @Comment({ - "To activate the restricted user feature you need", - "to enable this option and configure the AllowedRestrictedUser field."}) - public static final Property ENABLE_RESTRICTED_USERS = - newProperty("settings.restrictions.AllowRestrictedUser", true); - - @Comment({ - "The restricted user feature will kick players listed below", - "if they don't match the defined IP address. Names are case-insensitive.", - "You can use * as wildcard (127.0.0.*), or regex with a \"regex:\" prefix regex:127\\.0\\.0\\..*", - "Example:", - " AllowedRestrictedUser:", - " - playername;127.0.0.1", - " - playername;regex:127\\.0\\.0\\..*"}) - public static final Property> RESTRICTED_USERS = - newLowercaseStringSetProperty("settings.restrictions.AllowedRestrictedUser", - "server_land;127.0.0.1","server;127.0.0.1","bukkit;127.0.0.1","purpur;127.0.0.1", - "system;127.0.0.1","admin;127.0.0.1","md_5;127.0.0.1","administrator;127.0.0.1","notch;127.0.0.1", - "spigot;127.0.0.1","bukkit;127.0.0.1","bukkitcraft;127.0.0.1","paperclip;127.0.0.1","papermc;127.0.0.1", - "spigotmc;127.0.0.1","root;127.0.0.1","console;127.0.0.1","purpur;127.0.0.1","authme;127.0.0.1", - "owner;127.0.0.1"); - - @Comment("Ban unknown IPs trying to log in with a restricted username?") - public static final Property BAN_UNKNOWN_IP = - newProperty("settings.restrictions.banUnsafedIP", false); - - @Comment("Should unregistered players be kicked immediately?") - public static final Property KICK_NON_REGISTERED = - newProperty("settings.restrictions.kickNonRegistered", false); - - @Comment("Should players be kicked on wrong password?") - public static final Property KICK_ON_WRONG_PASSWORD = - newProperty("settings.restrictions.kickOnWrongPassword", false); - - @Comment({ - "Should not logged in players be teleported to the spawn?", - "After the authentication they will be teleported back to", - "their normal position."}) - public static final Property TELEPORT_UNAUTHED_TO_SPAWN = - newProperty("settings.restrictions.teleportUnAuthedToSpawn", false); - - @Comment("Can unregistered players walk around?") - public static final Property ALLOW_UNAUTHED_MOVEMENT = - newProperty("settings.restrictions.allowMovement", false); - - @Comment({ - "After how many seconds should players who fail to login or register", - "be kicked? Set to 0 to disable."}) - public static final Property TIMEOUT = - newProperty("settings.restrictions.timeout", 120); - - @Comment("Regex pattern of allowed characters in the player name.") - public static final Property ALLOWED_NICKNAME_CHARACTERS = - newProperty("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*"); - - - @Comment({ - "How far can unregistered players walk?", - "Set to 0 for unlimited radius" - }) - public static final Property ALLOWED_MOVEMENT_RADIUS = - newProperty("settings.restrictions.allowedMovementRadius", 0); - - @Comment("Should we protect the player inventory before logging in? Requires ProtocolLib.") - public static final Property PROTECT_INVENTORY_BEFORE_LOGIN = - newProperty("settings.restrictions.ProtectInventoryBeforeLogIn", false); - - @Comment("Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.") - public static final Property DENY_TABCOMPLETE_BEFORE_LOGIN = - newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", false); - - @Comment({ - "Should we display all other accounts from a player when he joins?", - "permission: /authme.admin.accounts"}) - public static final Property DISPLAY_OTHER_ACCOUNTS = - newProperty("settings.restrictions.displayOtherAccounts", false); - - @Comment("Spawn priority; values: authme, essentials, cmi, multiverse, default") - public static final Property SPAWN_PRIORITY = - newProperty("settings.restrictions.spawnPriority", "authme,essentials,cmi,multiverse,default"); - - @Comment("Maximum Login authorized by IP") - public static final Property MAX_LOGIN_PER_IP = - newProperty("settings.restrictions.maxLoginPerIp", 3); - - @Comment("Maximum Join authorized by IP") - public static final Property MAX_JOIN_PER_IP = - newProperty("settings.restrictions.maxJoinPerIp", 3); - - @Comment("AuthMe will NEVER teleport players if set to true!") - public static final Property NO_TELEPORT = - newProperty("settings.restrictions.noTeleport", false); - - @Comment({ - "Regex syntax for allowed chars in passwords. The default [!-~] allows all visible ASCII", - "characters, which is what we recommend. See also http://asciitable.com", - "You can test your regex with https://regex101.com" - }) - public static final Property ALLOWED_PASSWORD_REGEX = - newProperty("settings.restrictions.allowedPasswordCharacters", "[!-~]*"); - - @Comment("Regex syntax for allowed chars in email.") - public static final Property ALLOWED_EMAIL_REGEX = - newProperty("settings.restrictions.allowedEmailCharacters", "^[A-Za-z0-9_.]{3,20}@(qq|outlook|163|gmail|icloud)\\.com$"); - - - @Comment("Force survival gamemode when player joins?") - public static final Property FORCE_SURVIVAL_MODE = - newProperty("settings.GameMode.ForceSurvivalMode", false); - - @Comment({ - "Below you can list all account names that AuthMe will ignore", - "for registration or login. Configure it at your own risk!!", - "This option adds compatibility with BuildCraft and some other mods.", - "It is case-insensitive! Example:", - "UnrestrictedName:", - "- 'npcPlayer'", - "- 'npcPlayer2'" - }) - public static final Property> UNRESTRICTED_NAMES = - newLowercaseStringSetProperty("settings.unrestrictions.UnrestrictedName"); - - - @Comment({ - "Below you can list all inventories names that AuthMe will ignore", - "for registration or login. Configure it at your own risk!!", - "This option adds compatibility with some mods.", - "It is case-insensitive! Example:", - "UnrestrictedInventories:", - "- 'myCustomInventory1'", - "- 'myCustomInventory2'" - }) - public static final Property> UNRESTRICTED_INVENTORIES = - newLowercaseStringSetProperty("settings.unrestrictions.UnrestrictedInventories"); - - @Comment("Should we check unrestricted inventories strictly? (Original behavior)") - public static final Property STRICT_UNRESTRICTED_INVENTORIES_CHECK = - newProperty("settings.unrestrictions.StrictUnrestrictedInventoriesCheck", true); - - - private RestrictionSettings() { - - } - -} diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java deleted file mode 100644 index b1d7c4ae..00000000 --- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java +++ /dev/null @@ -1,203 +0,0 @@ -package fr.xephi.authme.settings.properties; - -import ch.jalu.configme.Comment; -import ch.jalu.configme.SettingsHolder; -import ch.jalu.configme.properties.Property; -import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.settings.EnumSetProperty; - -import java.util.Set; - -import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty; -import static ch.jalu.configme.properties.PropertyInitializer.newProperty; - -public final class SecuritySettings implements SettingsHolder { - - @Comment({"Stop the server if we can't contact the sql database", - "Take care with this, if you set this to false,", - "AuthMe will automatically disable and the server won't be protected!"}) - public static final Property STOP_SERVER_ON_PROBLEM = - newProperty("Security.SQLProblem.stopServer", false); - - @Comment({"Should we let Bedrock players login automatically?", - "(Requires hookFloodgate to be true & floodgate loaded)", - "(**THIS IS SAFE DO NOT WORRY**)"}) - public static final Property FORCE_LOGIN_BEDROCK = - newProperty("3rdPartyFeature.features.bedrockAutoLogin", false); - - @Comment("Should we purge data on non-registered players quit?") - public static final Property PURGE_DATA_ON_QUIT = - newProperty("3rdPartyFeature.features.purgeData.purgeOnQuit", false); - - @Comment("Which world's player data should be deleted?(Enter the world *FOLDER* name where your players first logged in)") - public static final Property DELETE_PLAYER_DATA_WORLD = - newProperty("3rdPartyFeature.features.purgeData.purgeWorldFolderName", "world"); - @Comment("Enable the new feature to prevent ghost players?") - public static final Property ANTI_GHOST_PLAYERS = - newProperty("3rdPartyFeature.fixes.antiGhostPlayer", false); - - @Comment({"(MC1.13- only)", - "Should we fix the shulker crash bug with advanced method?"}) - public static final Property ADVANCED_SHULKER_FIX = - newProperty("3rdPartyFeature.fixes.advancedShulkerFix", false); - - @Comment("Should we fix the location when players logged in the portal?") - public static final Property LOGIN_LOC_FIX_SUB_PORTAL = - newProperty("3rdPartyFeature.fixes.loginLocationFix.fixPortalStuck", false); - - @Comment("Should we fix the location when players logged underground?") - public static final Property LOGIN_LOC_FIX_SUB_UNDERGROUND = - newProperty("3rdPartyFeature.fixes.loginLocationFix.fixGroundStuck", false); - - @Comment("Copy AuthMe log output in a separate file as well?") - public static final Property USE_LOGGING = - newProperty("Security.console.logConsole", true); - - @Comment({"Query haveibeenpwned.com with a hashed version of the password.", - "This is used to check whether it is safe."}) - public static final Property HAVE_I_BEEN_PWNED_CHECK = - newProperty("Security.account.haveIBeenPwned.check", false); - - @Comment({"If the password is used more than this number of times, it is considered unsafe."}) - public static final Property HAVE_I_BEEN_PWNED_LIMIT = - newProperty("Security.account.haveIBeenPwned.limit", 0); - - @Comment("Enable captcha when a player uses wrong password too many times") - public static final Property ENABLE_LOGIN_FAILURE_CAPTCHA = - newProperty("Security.captcha.useCaptcha", false); - - @Comment("Check for updates on enabled from GitHub?") - public static final Property CHECK_FOR_UPDATES = - newProperty("Plugin.updates.checkForUpdates", true); - - @Comment("Should we show the AuthMe banner on startup?") - public static final Property SHOW_STARTUP_BANNER = - newProperty("Plugin.banners.showBanners", true); - - @Comment("Max allowed tries before a captcha is required") - public static final Property MAX_LOGIN_TRIES_BEFORE_CAPTCHA = - newProperty("Security.captcha.maxLoginTry", 8); - - @Comment("Captcha length") - public static final Property CAPTCHA_LENGTH = - newProperty("Security.captcha.captchaLength", 6); - - @Comment("Minutes after which login attempts count is reset for a player") - public static final Property CAPTCHA_COUNT_MINUTES_BEFORE_RESET = - newProperty("Security.captcha.captchaCountReset", 120); - - @Comment("Require captcha before a player may register?") - public static final Property ENABLE_CAPTCHA_FOR_REGISTRATION = - newProperty("Security.captcha.requireForRegistration", false); - - @Comment("Minimum length of password") - public static final Property MIN_PASSWORD_LENGTH = - newProperty("settings.security.minPasswordLength", 8); - - @Comment("Maximum length of password") - public static final Property MAX_PASSWORD_LENGTH = - newProperty("settings.security.passwordMaxLength", 26); - - @Comment({ - "Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512,", - "MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,", - "PBKDF2DJANGO, WORDPRESS, ROYALAUTH, ARGON2, NOCRYPT, CUSTOM (for developers only). See full list at", - "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/hash_algorithms.md", - "If you use ARGON2, check that you have the argon2 c library on your system" - }) - public static final Property PASSWORD_HASH = - newProperty(HashAlgorithm.class, "settings.security.passwordHash", HashAlgorithm.SHA256); - - @Comment({ - "If a password check fails, AuthMe will also try to check with the following hash methods.", - "Use this setting when you change from one hash method to another.", - "AuthMe will update the password to the new hash. Example:", - "legacyHashes:", - "- 'SHA1'" - }) - public static final Property> LEGACY_HASHES = - new EnumSetProperty<>(HashAlgorithm.class, "settings.security.legacyHashes"); - - @Comment("Salt length for the SALTED2MD5 MD5(MD5(password)+salt)") - public static final Property DOUBLE_MD5_SALT_LENGTH = - newProperty("settings.security.doubleMD5SaltLength", 8); - - @Comment("Number of rounds to use if passwordHash is set to PBKDF2. Default is 10000") - public static final Property PBKDF2_NUMBER_OF_ROUNDS = - newProperty("settings.security.pbkdf2Rounds", 10000); - - @Comment({"Prevent unsafe passwords from being used; put them in lowercase!", - "You should always set 'help' as unsafePassword due to possible conflicts.", - "unsafePasswords:", - "- '123456'", - "- 'password'", - "- 'help'"}) - public static final Property> UNSAFE_PASSWORDS = - newLowercaseStringSetProperty("settings.security.unsafePasswords", - "12345678", "password", "qwertyui", "123456789", "87654321", "1234567890", "asdfghjkl","zxcvbnm,","asdfghjk","12312312","123123123","32132132","321321321"); - - @Comment("Tempban a user's IP address if they enter the wrong password too many times") - public static final Property TEMPBAN_ON_MAX_LOGINS = - newProperty("Security.tempban.enableTempban", false); - - @Comment("How many times a user can attempt to login before their IP being tempbanned") - public static final Property MAX_LOGIN_TEMPBAN = - newProperty("Security.tempban.maxLoginTries", 8); - - @Comment({"The length of time a IP address will be tempbanned in minutes", - "Default: 480 minutes, or 8 hours"}) - public static final Property TEMPBAN_LENGTH = - newProperty("Security.tempban.tempbanLength", 480); - - @Comment({"How many minutes before resetting the count for failed logins by IP and username", - "Default: 480 minutes (8 hours)"}) - public static final Property TEMPBAN_MINUTES_BEFORE_RESET = - newProperty("Security.tempban.minutesBeforeCounterReset", 480); - - @Comment({"The command to execute instead of using the internal ban system, empty if disabled.", - "Available placeholders: %player%, %ip%"}) - public static final Property TEMPBAN_CUSTOM_COMMAND = - newProperty("Security.tempban.customCommand", ""); - - @Comment("Number of characters a recovery code should have (0 to disable)") - public static final Property RECOVERY_CODE_LENGTH = - newProperty("Security.recoveryCode.length", 8); - - @Comment("How many hours is a recovery code valid for?") - public static final Property RECOVERY_CODE_HOURS_VALID = - newProperty("Security.recoveryCode.validForHours", 6); - - @Comment("Max number of tries to enter recovery code") - public static final Property RECOVERY_CODE_MAX_TRIES = - newProperty("Security.recoveryCode.maxTries", 4); - - @Comment({"How long a player has after password recovery to change their password", - "without logging in. This is in minutes.", - "Default: 2 minutes"}) - public static final Property PASSWORD_CHANGE_TIMEOUT = - newProperty("Security.recoveryCode.passwordChangeTimeout", 5); - - @Comment({ - "Seconds a user has to wait for before a password recovery mail may be sent again", - "This prevents an attacker from abusing AuthMe's email feature." - }) - public static final Property EMAIL_RECOVERY_COOLDOWN_SECONDS = - newProperty("Security.emailRecovery.cooldown", 60); - - @Comment({ - "The mail shown using /email show will be partially hidden", - "E.g. (if enabled)", - " original email: my.email@example.com", - " hidden email: my.***@***mple.com" - }) - public static final Property USE_EMAIL_MASKING = - newProperty("Security.privacy.enableEmailMasking", false); - - @Comment("Minutes after which a verification code will expire") - public static final Property VERIFICATION_CODE_EXPIRATION_MINUTES = - newProperty("Security.privacy.verificationCodeExpiration", 10); - - private SecuritySettings() { - } - -} diff --git a/src/main/java/fr/xephi/authme/task/CleanupTask.java b/src/main/java/fr/xephi/authme/task/CleanupTask.java deleted file mode 100644 index 4f40ddb2..00000000 --- a/src/main/java/fr/xephi/authme/task/CleanupTask.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.xephi.authme.task; - -import ch.jalu.injector.factory.SingletonStore; -import com.github.Anon8281.universalScheduler.UniversalRunnable; -import fr.xephi.authme.initialization.HasCleanup; - -import javax.inject.Inject; - -/** - * Task run periodically to invoke the cleanup task on services. - */ -public class CleanupTask extends UniversalRunnable { - - @Inject - private SingletonStore hasCleanupStore; - - CleanupTask() { - } - - @Override - public void run() { - hasCleanupStore.retrieveAllOfType() - .forEach(HasCleanup::performCleanup); - } -} diff --git a/src/main/java/fr/xephi/authme/task/MessageTask.java b/src/main/java/fr/xephi/authme/task/MessageTask.java deleted file mode 100644 index dd11e8ef..00000000 --- a/src/main/java/fr/xephi/authme/task/MessageTask.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.xephi.authme.task; - -import com.github.Anon8281.universalScheduler.UniversalRunnable; -import org.bukkit.entity.Player; - -/** - * Message shown to a player in a regular interval as long as he is not logged in. - */ -public class MessageTask extends UniversalRunnable { - - private final Player player; - private final String[] message; - private boolean isMuted; - - /* - * Constructor. - */ - public MessageTask(Player player, String[] lines) { - this.player = player; - this.message = lines; - isMuted = false; - } - - public void setMuted(boolean isMuted) { - this.isMuted = isMuted; - } - - @Override - public void run() { - if (!isMuted) { - player.sendMessage(message); - } - } -} diff --git a/src/main/java/fr/xephi/authme/task/TimeoutTask.java b/src/main/java/fr/xephi/authme/task/TimeoutTask.java deleted file mode 100644 index 60aac741..00000000 --- a/src/main/java/fr/xephi/authme/task/TimeoutTask.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.xephi.authme.task; - -import fr.xephi.authme.data.auth.PlayerCache; -import org.bukkit.entity.Player; - -/** - * Kicks a player if he hasn't logged in (scheduled to run after a configured delay). - */ -public class TimeoutTask implements Runnable { - - private final Player player; - private final String message; - private final PlayerCache playerCache; - - /** - * Constructor for TimeoutTask. - * - * @param player the player to check - * @param message the kick message - * @param playerCache player cache instance - */ - public TimeoutTask(Player player, String message, PlayerCache playerCache) { - this.message = message; - this.player = player; - this.playerCache = playerCache; - } - - @Override - public void run() { - if (!playerCache.isAuthenticated(player.getName())) { - player.kickPlayer(message); - } - } -} diff --git a/src/main/java/fr/xephi/authme/task/Updater.java b/src/main/java/fr/xephi/authme/task/Updater.java deleted file mode 100644 index 5616d88a..00000000 --- a/src/main/java/fr/xephi/authme/task/Updater.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.task; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URL; -import java.util.Scanner; - -public class Updater { - private final String currentVersion; - private String latestVersion; - private static boolean isUpdateAvailable = false; - private static final String owner = "HaHaWTH"; - private static final String repo = "AuthMeReReloaded"; - private static final String UPDATE_URL = "https://api.github.com/repos/" + owner + "/" + repo + "/releases/latest"; - - public Updater(String currentVersion) { - this.currentVersion = currentVersion; - } - - - /** - * Check if there is an update available - * Note: This method will perform a network request! - * - * @return true if there is an update available, false otherwise - */ - public boolean isUpdateAvailable() { - URI uri = URI.create(UPDATE_URL); - try { - URL url = uri.toURL(); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(10000); - conn.setReadTimeout(10000); - Scanner scanner = new Scanner(conn.getInputStream()); - String response = scanner.useDelimiter("\\Z").next(); - scanner.close(); - String latestVersion = response.substring(response.indexOf("tag_name") + 11); - latestVersion = latestVersion.substring(0, latestVersion.indexOf("\"")); - this.latestVersion = latestVersion; - isUpdateAvailable = !currentVersion.equals(latestVersion); - return isUpdateAvailable; - } catch (IOException ignored) { - this.latestVersion = null; - isUpdateAvailable = false; - return false; - } - } - - public String getLatestVersion() { - return latestVersion; - } - - public String getCurrentVersion() { - return currentVersion; - } - - /** - * Returns true if there is an update available, false otherwise - * Must be called after {@link Updater#isUpdateAvailable()} - * - * @return A boolean indicating whether there is an update available - */ - public static boolean hasUpdate() { - return isUpdateAvailable; - } -} diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java b/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java deleted file mode 100644 index ea009604..00000000 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java +++ /dev/null @@ -1,227 +0,0 @@ -package fr.xephi.authme.task.purge; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.service.PluginHookService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PurgeSettings; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; - -import javax.inject.Inject; -import java.io.File; -import java.util.Collection; -import java.util.Locale; - -import static fr.xephi.authme.util.FileUtils.makePath; - -/** - * Executes the purge operations. - */ -public class PurgeExecutor { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PurgeExecutor.class); - - @Inject - private Settings settings; - - @Inject - private DataSource dataSource; - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private PluginHookService pluginHookService; - - @Inject - private BukkitService bukkitService; - - @Inject - private Server server; - - PurgeExecutor() { - } - - /** - * Performs the purge operations, i.e. deletes data and removes the files associated with the given - * players and names. - * - * @param players the players to purge - * @param names names to purge - */ - public void executePurge(Collection players, Collection names) { - // Purge other data - purgeFromAuthMe(names); - purgeEssentials(players); - purgeDat(players); - purgeLimitedCreative(names); - purgeAntiXray(names); - purgePermissions(players); - } - - /** - * Purges data from the AntiXray plugin. - * - * @param cleared the players whose data should be cleared - */ - synchronized void purgeAntiXray(Collection cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_ANTI_XRAY_FILE)) { - return; - } - - int i = 0; - File dataFolder = new File(makePath(".", "plugins", "AntiXRayData", "PlayerData")); - if (!dataFolder.exists() || !dataFolder.isDirectory()) { - return; - } - - for (String file : dataFolder.list()) { - if (cleared.contains(file.toLowerCase(Locale.ROOT))) { - File playerFile = new File(dataFolder, file); - if (playerFile.exists() && playerFile.delete()) { - i++; - } - } - } - - logger.info("AutoPurge: Removed " + i + " AntiXRayData Files"); - } - - /** - * Deletes the given accounts from AuthMe. - * - * @param names the name of the accounts to delete - */ - synchronized void purgeFromAuthMe(Collection names) { - dataSource.purgeRecords(names); - //TODO ljacqu 20160717: We shouldn't output namedBanned.size() but the actual total that was deleted - logger.info(ChatColor.GOLD + "Deleted " + names.size() + " user accounts"); - } - - /** - * Purges data from the LimitedCreative plugin. - * - * @param cleared the players whose data should be cleared - */ - synchronized void purgeLimitedCreative(Collection cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_LIMITED_CREATIVE_INVENTORIES)) { - return; - } - - int i = 0; - File dataFolder = new File(makePath(".", "plugins", "LimitedCreative", "inventories")); - if (!dataFolder.exists() || !dataFolder.isDirectory()) { - return; - } - for (String file : dataFolder.list()) { - String name = file; - int idx; - idx = file.lastIndexOf("_creative.yml"); - if (idx != -1) { - name = name.substring(0, idx); - } else { - idx = file.lastIndexOf("_adventure.yml"); - if (idx != -1) { - name = name.substring(0, idx); - } else { - idx = file.lastIndexOf(".yml"); - if (idx != -1) { - name = name.substring(0, idx); - } - } - } - if (name.equals(file)) { - continue; - } - if (cleared.contains(name.toLowerCase(Locale.ROOT))) { - File dataFile = new File(dataFolder, file); - if (dataFile.exists() && dataFile.delete()) { - i++; - } - } - } - logger.info("AutoPurge: Removed " + i + " LimitedCreative Survival, Creative and Adventure files"); - } - - /** - * Removes the .dat file of the given players. - * - * @param cleared list of players to clear - */ - synchronized void purgeDat(Collection cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_PLAYER_DAT)) { - return; - } - - int i = 0; - File dataFolder = new File(server.getWorldContainer(), - makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players")); - - for (OfflinePlayer offlinePlayer : cleared) { - File playerFile = new File(dataFolder, offlinePlayer.getUniqueId() + ".dat"); - if (playerFile.delete()) { - i++; - } - } - - logger.info("AutoPurge: Removed " + i + " .dat Files"); - } - - /** - * Removes the Essentials userdata file of each given player. - * - * @param cleared list of players to clear - */ - synchronized void purgeEssentials(Collection cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_ESSENTIALS_FILES)) { - return; - } - - File essentialsDataFolder = pluginHookService.getEssentialsDataFolder(); - if (essentialsDataFolder == null) { - logger.info("Cannot purge Essentials: plugin is not loaded"); - return; - } - - final File userDataFolder = new File(essentialsDataFolder, "userdata"); - if (!userDataFolder.exists() || !userDataFolder.isDirectory()) { - return; - } - - int deletedFiles = 0; - for (OfflinePlayer offlinePlayer : cleared) { - File playerFile = new File(userDataFolder, offlinePlayer.getUniqueId() + ".yml"); - if (playerFile.exists() && playerFile.delete()) { - deletedFiles++; - } - } - - logger.info("AutoPurge: Removed " + deletedFiles + " EssentialsFiles"); - } - - /** - * Removes permission data (groups a user belongs to) for the given players. - * - * @param cleared the players to remove data for - */ - synchronized void purgePermissions(Collection cleared) { - if (!settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS)) { - return; - } - - for (OfflinePlayer offlinePlayer : cleared) { - if (!permissionsManager.loadUserData(offlinePlayer)) { - logger.warning("Unable to purge the permissions of user " + offlinePlayer + "!"); - continue; - } - permissionsManager.removeAllGroups(offlinePlayer); - } - - logger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); - } -} diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeService.java b/src/main/java/fr/xephi/authme/task/purge/PurgeService.java deleted file mode 100644 index 880d5118..00000000 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeService.java +++ /dev/null @@ -1,123 +0,0 @@ -package fr.xephi.authme.task.purge; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.service.BukkitService; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PurgeSettings; -import fr.xephi.authme.util.Utils; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; - -import javax.inject.Inject; -import java.util.Calendar; -import java.util.Collection; -import java.util.Set; - -import static fr.xephi.authme.util.Utils.logAndSendMessage; - -/** - * Initiates purge tasks. - */ -public class PurgeService { - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PurgeService.class); - - @Inject - private BukkitService bukkitService; - - @Inject - private DataSource dataSource; - - @Inject - private Settings settings; - - @Inject - private PermissionsManager permissionsManager; - - @Inject - private PurgeExecutor purgeExecutor; - - /** Keeps track of whether a purge task is currently running. */ - private boolean isPurging = false; - - PurgeService() { - } - - /** - * Purges players from the database. Runs on startup if enabled. - */ - public void runAutoPurge() { - int daysBeforePurge = settings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER); - if (!settings.getProperty(PurgeSettings.USE_AUTO_PURGE)) { - return; - } else if (daysBeforePurge <= 0) { - logger.warning("Did not run auto purge: configured days before purging must be positive"); - return; - } - - logger.info("Automatically purging the database..."); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DATE, -daysBeforePurge); - long until = calendar.getTimeInMillis(); - - runPurge(null, until); - } - - /** - * Runs a purge with a specified last login threshold. Players who haven't logged in since the threshold - * will be purged. - * - * @param sender Sender running the command - * @param until The last login threshold in milliseconds - */ - public void runPurge(CommandSender sender, long until) { - //todo: note this should may run async because it may executes a SQL-Query - Set toPurge = dataSource.getRecordsToPurge(until); - if (Utils.isCollectionEmpty(toPurge)) { - logAndSendMessage(sender, "No players to purge"); - return; - } - - purgePlayers(sender, toPurge, bukkitService.getOfflinePlayers()); - } - - /** - * Purges the given list of player names. - * - * @param sender Sender running the command - * @param names The names to remove - * @param players Collection of OfflinePlayers (including those with the given names) - */ - public void purgePlayers(CommandSender sender, Set names, OfflinePlayer[] players) { - if (isPurging) { - logAndSendMessage(sender, "Purge is already in progress! Aborting purge request"); - return; - } - - isPurging = true; - PurgeTask purgeTask = new PurgeTask(this, permissionsManager, sender, names, players); - bukkitService.runTaskTimerAsynchronously(purgeTask, 0, 1); - } - - /** - * Set if a purge is currently in progress. - * - * @param purging True if purging. - */ - void setPurging(boolean purging) { - this.isPurging = purging; - } - - /** - * Perform purge operations for the given players and names. - * - * @param players the players (associated with the names) - * @param names the lowercase names - */ - void executePurge(Collection players, Collection names) { - purgeExecutor.executePurge(players, names); - } -} diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java b/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java deleted file mode 100644 index 15ab6552..00000000 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java +++ /dev/null @@ -1,130 +0,0 @@ -package fr.xephi.authme.task.purge; - -import com.github.Anon8281.universalScheduler.UniversalRunnable; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.permission.PlayerStatePermission; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.UUID; - -class PurgeTask extends UniversalRunnable { - - //how many players we should check for each tick - private static final int INTERVAL_CHECK = 5; - - private final ConsoleLogger logger = ConsoleLoggerFactory.get(PurgeTask.class); - private final PurgeService purgeService; - private final PermissionsManager permissionsManager; - private final UUID sender; - private final Set toPurge; - - private final OfflinePlayer[] offlinePlayers; - private final int totalPurgeCount; - - private int currentPage = 0; - - /** - * Constructor. - * - * @param service the purge service - * @param permissionsManager the permissions manager - * @param sender the sender who initiated the purge, or null - * @param toPurge lowercase names to purge - * @param offlinePlayers offline players to map to the names - */ - PurgeTask(PurgeService service, PermissionsManager permissionsManager, CommandSender sender, - Set toPurge, OfflinePlayer[] offlinePlayers) { - this.purgeService = service; - this.permissionsManager = permissionsManager; - - if (sender instanceof Player) { - this.sender = ((Player) sender).getUniqueId(); - } else { - this.sender = null; - } - - this.toPurge = toPurge; - this.totalPurgeCount = toPurge.size(); - this.offlinePlayers = offlinePlayers; - } - - @Override - public void run() { - if (toPurge.isEmpty()) { - //everything was removed - finish(); - return; - } - - Set playerPortion = new HashSet<>(INTERVAL_CHECK); - Set namePortion = new HashSet<>(INTERVAL_CHECK); - for (int i = 0; i < INTERVAL_CHECK; i++) { - int nextPosition = (currentPage * INTERVAL_CHECK) + i; - if (offlinePlayers.length <= nextPosition) { - //no more offline players on this page - break; - } - - OfflinePlayer offlinePlayer = offlinePlayers[nextPosition]; - if (offlinePlayer.getName() != null && toPurge.remove(offlinePlayer.getName().toLowerCase(Locale.ROOT))) { - if (!permissionsManager.loadUserData(offlinePlayer)) { - logger.warning("Unable to check if the user " + offlinePlayer.getName() + " can be purged!"); - continue; - } - if (!permissionsManager.hasPermissionOffline(offlinePlayer, PlayerStatePermission.BYPASS_PURGE)) { - playerPortion.add(offlinePlayer); - namePortion.add(offlinePlayer.getName()); - } - } - } - - if (!toPurge.isEmpty() && playerPortion.isEmpty()) { - logger.info("Finished lookup of offlinePlayers. Begin looking purging player names only"); - - //we went through all offlineplayers but there are still names remaining - for (String name : toPurge) { - if (!permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_PURGE)) { - namePortion.add(name); - } - } - toPurge.clear(); - } - - currentPage++; - purgeService.executePurge(playerPortion, namePortion); - if (currentPage % 20 == 0) { - int completed = totalPurgeCount - toPurge.size(); - sendMessage("[AuthMe] Purge progress " + completed + '/' + totalPurgeCount); - } - } - - private void finish() { - cancel(); - - // Show a status message - sendMessage(ChatColor.GREEN + "[AuthMe] Database has been purged successfully"); - - logger.info("Purge finished!"); - purgeService.setPurging(false); - } - - private void sendMessage(String message) { - if (sender == null) { - Bukkit.getConsoleSender().sendMessage(message); - } else { - Player player = Bukkit.getPlayer(sender); - if (player != null) { - player.sendMessage(message); - } - } - } -} diff --git a/src/main/java/fr/xephi/authme/util/AtomicIntervalCounter.java b/src/main/java/fr/xephi/authme/util/AtomicIntervalCounter.java deleted file mode 100644 index 2a50e660..00000000 --- a/src/main/java/fr/xephi/authme/util/AtomicIntervalCounter.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.xephi.authme.util; - -/** - * A thread-safe interval counter, allows to detect if an event happens more than 'threshold' times - * in the given 'interval'. - */ -public class AtomicIntervalCounter { - private final int threshold; - private final int interval; - private int count; - private long lastInsert; - - /** - * Constructs a new counter. - * - * @param threshold the threshold value of the counter. - * @param interval the counter interval in milliseconds. - */ - public AtomicIntervalCounter(int threshold, int interval) { - this.threshold = threshold; - this.interval = interval; - reset(); - } - - /** - * Resets the counter count. - */ - public synchronized void reset() { - count = 0; - lastInsert = 0; - } - - /** - * Increments the counter and returns true if the current count has reached the threshold value - * in the given interval, this will also reset the count value. - * - * @return true if the count has reached the threshold value. - */ - public synchronized boolean handle() { - long now = System.currentTimeMillis(); - if (now - lastInsert > interval) { - count = 1; - } else { - count++; - } - if (count > threshold) { - reset(); - return true; - } - lastInsert = now; - return false; - } -} diff --git a/src/main/java/fr/xephi/authme/util/ExceptionUtils.java b/src/main/java/fr/xephi/authme/util/ExceptionUtils.java deleted file mode 100644 index fd5ae885..00000000 --- a/src/main/java/fr/xephi/authme/util/ExceptionUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.util; - -import com.google.common.collect.Sets; - -import java.util.Set; - -/** - * Utilities for exceptions. - */ -public final class ExceptionUtils { - - private ExceptionUtils() { - } - - /** - * Returns the first throwable of the given {@code wantedThrowableType} by visiting the provided - * throwable and its causes recursively. - * - * @param wantedThrowableType the throwable type to find - * @param throwable the throwable to start with - * @param the desired throwable subtype - * @return the first throwable found of the given type, or null if none found - */ - public static T findThrowableInCause(Class wantedThrowableType, Throwable throwable) { - Set visitedObjects = Sets.newIdentityHashSet(); - Throwable currentThrowable = throwable; - while (currentThrowable != null && !visitedObjects.contains(currentThrowable)) { - if (wantedThrowableType.isInstance(currentThrowable)) { - return wantedThrowableType.cast(currentThrowable); - } - visitedObjects.add(currentThrowable); - currentThrowable = currentThrowable.getCause(); - } - return null; - } - - /** - * Format the information from a Throwable as string, retaining the type and its message. - * - * @param th the throwable to process - * @return string with the type of the Throwable and its message, e.g. "[IOException]: Could not open stream" - */ - public static String formatException(Throwable th) { - return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage(); - } -} diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java deleted file mode 100644 index 7f7ee4aa..00000000 --- a/src/main/java/fr/xephi/authme/util/FileUtils.java +++ /dev/null @@ -1,173 +0,0 @@ -package fr.xephi.authme.util; - -import com.google.common.io.Files; -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -import static java.lang.String.format; - -/** - * File utilities. - */ -public final class FileUtils { - - private static final DateTimeFormatter CURRENT_DATE_STRING_FORMATTER = - DateTimeFormatter.ofPattern("yyyyMMdd_HHmm"); - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(FileUtils.class); - - // Utility class - private FileUtils() { - } - - /** - * Copy a resource file (from the JAR) to the given file if it doesn't exist. - * - * @param destinationFile The file to check and copy to (outside of JAR) - * @param resourcePath Local path to the resource file (path to file within JAR) - * - * @return False if the file does not exist and could not be copied, true otherwise - */ - public static boolean copyFileFromResource(File destinationFile, String resourcePath) { - if (destinationFile.exists()) { - return true; - } else if (!createDirectory(destinationFile.getParentFile())) { - logger.warning("Cannot create parent directories for '" + destinationFile + "'"); - return false; - } - - try (InputStream is = getResourceFromJar(resourcePath)) { - if (is == null) { - logger.warning(format("Cannot copy resource '%s' to file '%s': cannot load resource", - resourcePath, destinationFile.getPath())); - } else { - java.nio.file.Files.copy(is, destinationFile.toPath()); - return true; - } - } catch (IOException e) { - logger.logException(format("Cannot copy resource '%s' to file '%s':", - resourcePath, destinationFile.getPath()), e); - } - return false; - } - - /** - * Creates the given directory. - * - * @param dir the directory to create - * @return true upon success, false otherwise - */ - public static boolean createDirectory(File dir) { - if (!dir.exists() && !dir.mkdirs()) { - logger.warning("Could not create directory '" + dir + "'"); - return false; - } - return dir.isDirectory(); - } - - /** - * Returns a JAR file as stream. Returns null if it doesn't exist. - * - * @param path the local path (starting from resources project, e.g. "config.yml" for 'resources/config.yml') - * @return the stream if the file exists, or false otherwise - */ - public static InputStream getResourceFromJar(String path) { - // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/' - final String normalizedPath = path.replace("\\", "/"); - return AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath); - } - - /** - * Delete a given directory and all its content. - * - * @param directory The directory to remove - */ - public static void purgeDirectory(File directory) { - if (!directory.isDirectory()) { - return; - } - File[] files = directory.listFiles(); - if (files == null) { - return; - } - for (File target : files) { - if (target.isDirectory()) { - purgeDirectory(target); - } - delete(target); - } - } - - /** - * Delete the given file or directory and log a message if it was unsuccessful. - * Method is null safe and does nothing when null is passed. - * - * @param file the file to delete - */ - public static void delete(File file) { - if (file != null) { - boolean result = file.delete(); - if (!result) { - logger.warning("Could not delete file '" + file + "'"); - } - } - } - - /** - * Creates the given file or throws an exception. - * - * @param file the file to create - */ - public static void create(File file) { - try { - boolean result = file.createNewFile(); - if (!result) { - throw new IllegalStateException("Could not create file '" + file + "'"); - } - } catch (IOException e) { - throw new IllegalStateException("Error while creating file '" + file + "'", e); - } - } - - /** - * Construct a file path from the given elements, i.e. separate the given elements by the file separator. - * - * @param elements The elements to create a path with - * - * @return The created path - */ - public static String makePath(String... elements) { - return String.join(File.separator, elements); - } - - /** - * Creates a textual representation of the current time (including minutes), e.g. useful for - * automatically generated backup files. - * - * @return string of the current time for use in file names - */ - public static String createCurrentTimeString() { - return LocalDateTime.now().format(CURRENT_DATE_STRING_FORMATTER); - } - - /** - * Returns a path to a new file (which doesn't exist yet) with a timestamp in the name in the same - * folder as the given file and containing the given file's filename. - * - * @param file the file based on which a new file path should be created - * @return path to a file suitably named for storing a backup - */ - public static String createBackupFilePath(File file) { - String filename = "backup_" + Files.getNameWithoutExtension(file.getName()) - + "_" + createCurrentTimeString() - + "." + Files.getFileExtension(file.getName()); - return makePath(file.getParent(), filename); - } -} diff --git a/src/main/java/fr/xephi/authme/util/InternetProtocolUtils.java b/src/main/java/fr/xephi/authme/util/InternetProtocolUtils.java deleted file mode 100644 index 03942154..00000000 --- a/src/main/java/fr/xephi/authme/util/InternetProtocolUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package fr.xephi.authme.util; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Utility class about the InternetProtocol - */ -public final class InternetProtocolUtils { - - // Utility class - private InternetProtocolUtils() { - } - - /** - * Checks if the specified address is a private or loopback address - * - * @param address address to check - * @return true if the address is a local (site and link) or loopback address, false otherwise - */ - public static boolean isLocalAddress(String address) { - try { - InetAddress inetAddress = InetAddress.getByName(address); - - // Examples: 127.0.0.1, localhost or [::1] - return isLoopbackAddress(address) - // Example: 10.0.0.0, 172.16.0.0, 192.168.0.0, fec0::/10 (deprecated) - // Ref: https://en.wikipedia.org/wiki/IP_address#Private_addresses - || inetAddress.isSiteLocalAddress() - // Example: 169.254.0.0/16, fe80::/10 - // Ref: https://en.wikipedia.org/wiki/IP_address#Address_autoconfiguration - || inetAddress.isLinkLocalAddress() - // non deprecated unique site-local that java doesn't check yet -> fc00::/7 - || isIPv6UniqueSiteLocal(inetAddress); - } catch (UnknownHostException e) { - return false; - } - } - - /** - * Checks if the specified address is a loopback address. This can be one of the following: - *

    - *
  • 127.0.0.1
  • - *
  • localhost
  • - *
  • [::1]
  • - *
- * - * @param address address to check - * @return true if the address is a loopback one - */ - public static boolean isLoopbackAddress(String address) { - try { - InetAddress inetAddress = InetAddress.getByName(address); - return inetAddress.isLoopbackAddress(); - } catch (UnknownHostException e) { - return false; - } - } - - private static boolean isLoopbackAddress(InetAddress address) { - return address.isLoopbackAddress(); - } - - private static boolean isIPv6UniqueSiteLocal(InetAddress address) { - // ref: https://en.wikipedia.org/wiki/Unique_local_address - - // currently undefined but could be used in the near future fc00::/8 - return (address.getAddress()[0] & 0xFF) == 0xFC - // in use for unique site-local fd00::/8 - || (address.getAddress()[0] & 0xFF) == 0xFD; - } -} diff --git a/src/main/java/fr/xephi/authme/util/PlayerUtils.java b/src/main/java/fr/xephi/authme/util/PlayerUtils.java deleted file mode 100644 index 3c9b6f4f..00000000 --- a/src/main/java/fr/xephi/authme/util/PlayerUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -package fr.xephi.authme.util; - -import org.bukkit.entity.Player; - -/** - * Player utilities. - */ -public final class PlayerUtils { - - // Utility class - private PlayerUtils() { - } - private static final boolean isLeavesServer = Utils.isClassLoaded("top.leavesmc.leaves.LeavesConfig") || Utils.isClassLoaded("org.leavesmc.leaves.LeavesConfig"); - - /** - * Returns the IP of the given player. - * - * @param player The player to return the IP address for - * @return The player's IP address - */ - public static String getPlayerIp(Player player) { - return player.getAddress().getAddress().getHostAddress(); - } - - /** - * Returns if the player is an NPC or not. - * - * @param player The player to check - * @return True if the player is an NPC, false otherwise - */ - public static boolean isNpc(Player player) { - if (isLeavesServer) { - return player.hasMetadata("NPC") || player.getAddress() == null; - } else { - return player.hasMetadata("NPC"); - } - } - -} diff --git a/src/main/java/fr/xephi/authme/util/RandomStringUtils.java b/src/main/java/fr/xephi/authme/util/RandomStringUtils.java deleted file mode 100644 index 58018477..00000000 --- a/src/main/java/fr/xephi/authme/util/RandomStringUtils.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.util; - -import java.security.SecureRandom; -import java.util.Random; - -/** - * Utility for generating random strings. - */ -public final class RandomStringUtils { - - private static final char[] CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - private static final Random RANDOM = new SecureRandom(); - private static final int NUM_INDEX = 10; - private static final int LOWER_ALPHANUMERIC_INDEX = 36; - private static final int HEX_MAX_INDEX = 16; - - // Utility class - private RandomStringUtils() { - } - - /** - * Generate a string of the given length consisting of random characters within the range [0-9a-z]. - * - * @param length The length of the random string to generate - * @return The random string - */ - public static String generate(int length) { - return generateString(length, LOWER_ALPHANUMERIC_INDEX); - } - - /** - * Generate a random hexadecimal string of the given length. In other words, the generated string - * contains characters only within the range [0-9a-f]. - * - * @param length The length of the random string to generate - * @return The random hexadecimal string - */ - public static String generateHex(int length) { - return generateString(length, HEX_MAX_INDEX); - } - - /** - * Generate a random numbers string of the given length. In other words, the generated string - * contains characters only within the range [0-9]. - * - * @param length The length of the random string to generate - * @return The random numbers string - */ - public static String generateNum(int length) { - return generateString(length, NUM_INDEX); - } - - /** - * Generate a random string with digits and lowercase and uppercase letters. The result of this - * method matches the pattern [0-9a-zA-Z]. - * - * @param length The length of the random string to generate - * @return The random string - */ - public static String generateLowerUpper(int length) { - return generateString(length, CHARS.length); - } - - private static String generateString(int length, int maxIndex) { - if (length < 0) { - throw new IllegalArgumentException("Length must be positive but was " + length); - } - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; ++i) { - sb.append(CHARS[RANDOM.nextInt(maxIndex)]); - } - return sb.toString(); - } - -} diff --git a/src/main/java/fr/xephi/authme/util/StringUtils.java b/src/main/java/fr/xephi/authme/util/StringUtils.java deleted file mode 100644 index 8a863678..00000000 --- a/src/main/java/fr/xephi/authme/util/StringUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -package fr.xephi.authme.util; - -import net.ricecode.similarity.LevenshteinDistanceStrategy; -import net.ricecode.similarity.StringSimilarityService; -import net.ricecode.similarity.StringSimilarityServiceImpl; - -/** - * Utility class for String operations. - */ -public final class StringUtils { - - // Utility class - private StringUtils() { - } - - /** - * Calculates the difference of two strings. - * - * @param first first string - * @param second second string - * @return the difference value - */ - public static double getDifference(String first, String second) { - // Make sure the strings are valid. - if (first == null || second == null) { - return 1.0; - } - - // Create a string similarity service instance, to allow comparison - StringSimilarityService service = new StringSimilarityServiceImpl(new LevenshteinDistanceStrategy()); - - // Determine the difference value, return the result - return Math.abs(service.score(first, second) - 1.0); - } - - /** - * Returns whether the given string contains any of the provided elements. - * - * @param str the string to analyze - * @param pieces the items to check the string for - * @return true if the string contains at least one of the items - */ - public static boolean containsAny(String str, Iterable pieces) { - if (str == null) { - return false; - } - for (String piece : pieces) { - if (piece != null && str.contains(piece)) { - return true; - } - } - return false; - } - - /** - * Null-safe method for checking whether a string is empty. Note that the string - * is trimmed, so this method also considers a string with whitespace as empty. - * - * @param str the string to verify - * @return true if the string is empty, false otherwise - */ - public static boolean isBlank(String str) { - return str == null || str.trim().isEmpty(); - } - - /** - * Checks that the given needle is in the middle of the haystack, i.e. that the haystack - * contains the needle and that it is not at the very start or end. - * - * @param needle the needle to search for - * @param haystack the haystack to search in - * @return true if the needle is in the middle of the word, false otherwise - */ - // Note ljacqu 20170314: `needle` is restricted to char type intentionally because something like - // isInsideString("11", "2211") would unexpectedly return true... - public static boolean isInsideString(char needle, String haystack) { - int index = haystack.indexOf(needle); - return index > 0 && index < haystack.length() - 1; - } -} diff --git a/src/main/java/fr/xephi/authme/util/TeleportUtils.java b/src/main/java/fr/xephi/authme/util/TeleportUtils.java deleted file mode 100644 index 4a043b17..00000000 --- a/src/main/java/fr/xephi/authme/util/TeleportUtils.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.xephi.authme.util; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.concurrent.CompletableFuture; - -/** - * This class is a utility class for handling async teleportation of players in game. - */ -public class TeleportUtils { - private static MethodHandle teleportAsyncMethodHandle; - - static { - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - teleportAsyncMethodHandle = lookup.findVirtual(Player.class, "teleportAsync", MethodType.methodType(CompletableFuture.class, Location.class)); - } catch (NoSuchMethodException | IllegalAccessException e) { - teleportAsyncMethodHandle = null; - // if not, set method handle to null - } - } - - /** - * Teleport a player to a specified location. - * - * @param player The player to be teleported - * @param location Where should the player be teleported - */ - public static void teleport(Player player, Location location) { - if (teleportAsyncMethodHandle != null) { - try { - teleportAsyncMethodHandle.invoke(player, location); - } catch (Throwable throwable) { - player.teleport(location); - } - } else { - player.teleport(location); - } - } -} diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java deleted file mode 100644 index 324a8eed..00000000 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ /dev/null @@ -1,119 +0,0 @@ -package fr.xephi.authme.util; - -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.output.ConsoleLoggerFactory; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; - -import java.util.Collection; -import java.util.regex.Pattern; - -/** - * Utility class for various operations used in the codebase. - */ -public final class Utils { - - /** Number of milliseconds in a minute. */ - public static final long MILLIS_PER_MINUTE = 60_000L; - - private static ConsoleLogger logger = ConsoleLoggerFactory.get(Utils.class); - - // Utility class - private Utils() { - } - - /** - * Compile Pattern sneaky without throwing Exception. - * - * @param pattern pattern string to compile - * - * @return the given regex compiled into Pattern object. - */ - public static Pattern safePatternCompile(String pattern) { - try { - return Pattern.compile(pattern); - } catch (Exception e) { - logger.warning("Failed to compile pattern '" + pattern + "' - defaulting to allowing everything"); - return Pattern.compile(".*?"); - } - } - - /** - * Returns whether the class exists in the current class loader. - * - * @param className the class name to check - * - * @return true if the class is loaded, false otherwise - */ - public static boolean isClassLoaded(String className) { - try { - Class.forName(className); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - - /** - * Sends a message to the given sender (null safe), and logs the message to the console. - * This method is aware that the command sender might be the console sender and avoids - * displaying the message twice in this case. - * - * @param sender the sender to inform - * @param message the message to log and send - */ - public static void logAndSendMessage(CommandSender sender, String message) { - logger.info(message); - // Make sure sender is not console user, which will see the message from ConsoleLogger already - if (sender != null && !(sender instanceof ConsoleCommandSender)) { - sender.sendMessage(message); - } - } - - /** - * Sends a warning to the given sender (null safe), and logs the warning to the console. - * This method is aware that the command sender might be the console sender and avoids - * displaying the message twice in this case. - * - * @param sender the sender to inform - * @param message the warning to log and send - */ - public static void logAndSendWarning(CommandSender sender, String message) { - logger.warning(message); - // Make sure sender is not console user, which will see the message from ConsoleLogger already - if (sender != null && !(sender instanceof ConsoleCommandSender)) { - sender.sendMessage(ChatColor.RED + message); - } - } - - /** - * Null-safe way to check whether a collection is empty or not. - * - * @param coll The collection to verify - * @return True if the collection is null or empty, false otherwise - */ - public static boolean isCollectionEmpty(Collection coll) { - return coll == null || coll.isEmpty(); - } - - /** - * Returns whether the given email is empty or equal to the standard "undefined" email address. - * - * @param email the email to check - * - * @return true if the email is empty - */ - public static boolean isEmailEmpty(String email) { - return StringUtils.isBlank(email) || "your@email.com".equalsIgnoreCase(email); - } - - private final static String[] serverVersion = Bukkit.getServer().getBukkitVersion() - .substring(0, Bukkit.getServer().getBukkitVersion().indexOf("-")) - .split("\\."); - - private final static int FIRST_VERSION = Integer.parseInt(serverVersion[0]); - public final static int MAJOR_VERSION = Integer.parseInt(serverVersion[1]); - public final static int MINOR_VERSION = serverVersion.length == 3 ? Integer.parseInt(serverVersion[2]) : 0; -} diff --git a/src/main/java/fr/xephi/authme/util/UuidUtils.java b/src/main/java/fr/xephi/authme/util/UuidUtils.java deleted file mode 100644 index be35a935..00000000 --- a/src/main/java/fr/xephi/authme/util/UuidUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -package fr.xephi.authme.util; - -import java.util.UUID; - -/** - * Utility class for various operations on UUID. - */ -public final class UuidUtils { - - // Utility class - private UuidUtils() { - } - - /** - * Returns the given string as an UUID or null. - * - * @param string the uuid to parse - * @return parsed UUID if succeeded or null - */ - public static UUID parseUuidSafely(String string) { - try { - return string == null ? null : UUID.fromString(string); - } catch (IllegalArgumentException ex) { - return null; - } - } -} diff --git a/src/main/java/fr/xephi/authme/util/expiring/Duration.java b/src/main/java/fr/xephi/authme/util/expiring/Duration.java deleted file mode 100644 index ecc86299..00000000 --- a/src/main/java/fr/xephi/authme/util/expiring/Duration.java +++ /dev/null @@ -1,72 +0,0 @@ -package fr.xephi.authme.util.expiring; - -import java.util.concurrent.TimeUnit; - -/** - * Represents a duration in time, defined by a time unit and a duration. - */ -public class Duration { - - private final long duration; - private final TimeUnit unit; - - /** - * Constructor. - * - * @param duration the duration - * @param unit the time unit in which {@code duration} is expressed - */ - public Duration(long duration, TimeUnit unit) { - this.duration = duration; - this.unit = unit; - } - - /** - * Creates a Duration object for the given duration and unit in the most suitable time unit. - * For example, {@code createWithSuitableUnit(120, TimeUnit.SECONDS)} will return a Duration - * object of 2 minutes. - *

- * This method only considers the time units days, hours, minutes, and seconds for the objects - * it creates. Conversion is done with {@link TimeUnit#convert} and so always rounds the - * results down. - *

- * Further examples: - * createWithSuitableUnit(299, TimeUnit.MINUTES); // 4 hours - * createWithSuitableUnit(700, TimeUnit.MILLISECONDS); // 0 seconds - * - * @param sourceDuration the duration - * @param sourceUnit the time unit the duration is expressed in - * @return Duration object using the most suitable time unit - */ - public static Duration createWithSuitableUnit(long sourceDuration, TimeUnit sourceUnit) { - long durationMillis = Math.abs(TimeUnit.MILLISECONDS.convert(sourceDuration, sourceUnit)); - - TimeUnit targetUnit; - if (durationMillis > 1000L * 60L * 60L * 24L) { - targetUnit = TimeUnit.DAYS; - } else if (durationMillis > 1000L * 60L * 60L) { - targetUnit = TimeUnit.HOURS; - } else if (durationMillis > 1000L * 60L) { - targetUnit = TimeUnit.MINUTES; - } else { - targetUnit = TimeUnit.SECONDS; - } - - long durationInTargetUnit = targetUnit.convert(sourceDuration, sourceUnit); - return new Duration(durationInTargetUnit, targetUnit); - } - - /** - * @return the duration - */ - public long getDuration() { - return duration; - } - - /** - * @return the time unit in which the duration is expressed - */ - public TimeUnit getTimeUnit() { - return unit; - } -} diff --git a/src/main/java/fr/xephi/authme/util/expiring/ExpiringMap.java b/src/main/java/fr/xephi/authme/util/expiring/ExpiringMap.java deleted file mode 100644 index 3bf19351..00000000 --- a/src/main/java/fr/xephi/authme/util/expiring/ExpiringMap.java +++ /dev/null @@ -1,138 +0,0 @@ -package fr.xephi.authme.util.expiring; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -/** - * Map with expiring entries. Following a configured amount of time after - * an entry has been inserted, the map will act as if the entry does not - * exist. - *

- * Time starts counting directly after insertion. Inserting a new entry with - * a key that already has a value will "reset" the expiration. Although the - * expiration can be redefined later on, only entries which are inserted - * afterwards will use the new expiration. - *

- * An expiration of {@code <= 0} will make the map expire all entries - * immediately after insertion. Note that the map does not remove expired - * entries automatically; this is only done when calling - * {@link #removeExpiredEntries()}. - * - * @param the key type - * @param the value type - */ -public class ExpiringMap { - - private final Map> entries = new ConcurrentHashMap<>(); - private long expirationMillis; - - /** - * Constructor. - * - * @param duration the duration of time after which entries expire - * @param unit the time unit in which {@code duration} is expressed - */ - public ExpiringMap(long duration, TimeUnit unit) { - setExpiration(duration, unit); - } - - /** - * Returns the value associated with the given key, - * if available and not expired. - * - * @param key the key to look up - * @return the associated value, or {@code null} if not available - */ - public V get(K key) { - ExpiringEntry value = entries.get(key); - if (value == null) { - return null; - } else if (System.currentTimeMillis() > value.getExpiration()) { - entries.remove(key); - return null; - } - return value.getValue(); - } - - /** - * Inserts a value for the given key. Overwrites a previous value - * for the key if it exists. - * - * @param key the key to insert a value for - * @param value the value to insert - */ - public void put(K key, V value) { - long expiration = System.currentTimeMillis() + expirationMillis; - entries.put(key, new ExpiringEntry<>(value, expiration)); - } - - /** - * Removes the value for the given key, if available. - * - * @param key the key to remove the value for - */ - public void remove(K key) { - entries.remove(key); - } - - /** - * Removes all entries which have expired from the internal structure. - */ - public void removeExpiredEntries() { - entries.entrySet().removeIf(entry -> System.currentTimeMillis() > entry.getValue().getExpiration()); - } - - /** - * Sets a new expiration duration. Note that already present entries - * will still make use of the old expiration. - * - * @param duration the duration of time after which entries expire - * @param unit the time unit in which {@code duration} is expressed - */ - public void setExpiration(long duration, TimeUnit unit) { - this.expirationMillis = unit.toMillis(duration); - } - - /** - * Returns whether this map is empty. This reflects the state of the - * internal map, which may contain expired entries only. The result - * may change after running {@link #removeExpiredEntries()}. - * - * @return true if map is really empty, false otherwise - */ - public boolean isEmpty() { - return entries.isEmpty(); - } - - /** - * @return the internal map - */ - protected Map> getEntries() { - return entries; - } - - /** - * Class holding a value paired with an expiration timestamp. - * - * @param the value type - */ - protected static final class ExpiringEntry { - - private final V value; - private final long expiration; - - ExpiringEntry(V value, long expiration) { - this.value = value; - this.expiration = expiration; - } - - V getValue() { - return value; - } - - long getExpiration() { - return expiration; - } - } -} diff --git a/src/main/java/fr/xephi/authme/util/expiring/ExpiringSet.java b/src/main/java/fr/xephi/authme/util/expiring/ExpiringSet.java deleted file mode 100644 index fea8fb31..00000000 --- a/src/main/java/fr/xephi/authme/util/expiring/ExpiringSet.java +++ /dev/null @@ -1,125 +0,0 @@ -package fr.xephi.authme.util.expiring; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -/** - * Set whose entries expire after a configurable amount of time. Once an entry - * has expired, the set will act as if the entry no longer exists. Time starts - * counting after the entry has been inserted. - *

- * Internally, expired entries are not guaranteed to be cleared automatically. - * A cleanup of all expired entries may be triggered with - * {@link #removeExpiredEntries()}. Adding an entry that is already present - * effectively resets its expiration. - * - * @param the type of the entries - */ -public class ExpiringSet { - - private Map entries = new ConcurrentHashMap<>(); - private long expirationMillis; - - /** - * Constructor. - * - * @param duration the duration of time after which entries expire - * @param unit the time unit in which {@code duration} is expressed - */ - public ExpiringSet(long duration, TimeUnit unit) { - setExpiration(duration, unit); - } - - /** - * Adds an entry to the set. - * - * @param entry the entry to add - */ - public void add(E entry) { - entries.put(entry, System.currentTimeMillis() + expirationMillis); - } - - /** - * Returns whether this set contains the given entry, if it hasn't expired. - * - * @param entry the entry to check - * @return true if the entry is present and not expired, false otherwise - */ - public boolean contains(E entry) { - Long expiration = entries.get(entry); - if (expiration == null) { - return false; - } else if (expiration > System.currentTimeMillis()) { - return true; - } else { - entries.remove(entry); - return false; - } - } - - /** - * Removes the given entry from the set (if present). - * - * @param entry the entry to remove - */ - public void remove(E entry) { - entries.remove(entry); - } - - /** - * Removes all entries from the set. - */ - public void clear() { - entries.clear(); - } - - /** - * Removes all entries which have expired from the internal structure. - */ - public void removeExpiredEntries() { - entries.entrySet().removeIf(entry -> System.currentTimeMillis() > entry.getValue()); - } - - /** - * Returns the duration of the entry until it expires (provided it is not removed or re-added). - * If the entry does not exist, a duration of -1 seconds is returned. - * - * @param entry the entry whose duration before it expires should be returned - * @return duration the entry will remain in the set (if there are not modifications) - */ - public Duration getExpiration(E entry) { - Long expiration = entries.get(entry); - if (expiration == null) { - return new Duration(-1, TimeUnit.SECONDS); - } - long stillPresentMillis = expiration - System.currentTimeMillis(); - if (stillPresentMillis < 0) { - entries.remove(entry); - return new Duration(-1, TimeUnit.SECONDS); - } - return Duration.createWithSuitableUnit(stillPresentMillis, TimeUnit.MILLISECONDS); - } - - /** - * Sets a new expiration duration. Note that already present entries - * will still make use of the old expiration. - * - * @param duration the duration of time after which entries expire - * @param unit the time unit in which {@code duration} is expressed - */ - public void setExpiration(long duration, TimeUnit unit) { - this.expirationMillis = unit.toMillis(duration); - } - - /** - * Returns whether this map is empty. This reflects the state of the - * internal map, which may contain expired entries only. The result - * may change after running {@link #removeExpiredEntries()}. - * - * @return true if map is really empty, false otherwise - */ - public boolean isEmpty() { - return entries.isEmpty(); - } -} diff --git a/src/main/java/fr/xephi/authme/util/expiring/TimedCounter.java b/src/main/java/fr/xephi/authme/util/expiring/TimedCounter.java deleted file mode 100644 index d6d8bba1..00000000 --- a/src/main/java/fr/xephi/authme/util/expiring/TimedCounter.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.xephi.authme.util.expiring; - -import java.util.concurrent.TimeUnit; - -/** - * Keeps a count per key which expires after a configurable amount of time. - *

- * Once the expiration of an entry has been reached, the counter resets - * to 0. The counter returns 0 rather than {@code null} for any given key. - * - * @param the type of the key - */ -public class TimedCounter extends ExpiringMap { - - /** - * Constructor. - * - * @param duration the duration of time after which entries expire - * @param unit the time unit in which {@code duration} is expressed - */ - public TimedCounter(long duration, TimeUnit unit) { - super(duration, unit); - } - - @Override - public Integer get(K key) { - Integer value = super.get(key); - return value == null ? 0 : value; - } - - /** - * Increments the value stored for the provided key. - * - * @param key the key to increment the counter for - */ - public void increment(K key) { - put(key, get(key) + 1); - } - - /** - * Decrements the value stored for the provided key. - * This method will NOT update the expiration. - * - * @param key the key to increment the counter for - */ - public void decrement(K key) { - ExpiringEntry e = getEntries().get(key); - - if (e != null) { - if (e.getValue() <= 0) { - remove(key); - } else { - getEntries().put(key, new ExpiringEntry<>(e.getValue() - 1, e.getExpiration())); - } - } - } - - /** - * Calculates the total of all non-expired entries in this counter. - * - * @return the total of all valid entries - */ - public int total() { - long currentTime = System.currentTimeMillis(); - return getEntries().values().stream() - .filter(entry -> currentTime <= entry.getExpiration()) - .map(ExpiringEntry::getValue) - .reduce(0, Integer::sum); - } -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/DependentTag.java b/src/main/java/fr/xephi/authme/util/lazytags/DependentTag.java deleted file mode 100644 index 5fb0cd3d..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/DependentTag.java +++ /dev/null @@ -1,35 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -import java.util.function.Function; - -/** - * Replaceable tag whose value depends on an argument. - * - * @param the argument type - */ -public class DependentTag implements Tag { - - private final String name; - private final Function replacementFunction; - - /** - * Constructor. - * - * @param name the tag (placeholder) that will be replaced - * @param replacementFunction the function producing the replacement - */ - public DependentTag(String name, Function replacementFunction) { - this.name = name; - this.replacementFunction = replacementFunction; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getValue(A argument) { - return replacementFunction.apply(argument); - } -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/SimpleTag.java b/src/main/java/fr/xephi/authme/util/lazytags/SimpleTag.java deleted file mode 100644 index a5bb58a2..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/SimpleTag.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -import java.util.function.Supplier; - -/** - * Tag to be replaced that does not depend on an argument. - * - * @param type of the argument (not used in this implementation) - */ -public class SimpleTag implements Tag { - - private final String name; - private final Supplier replacementFunction; - - public SimpleTag(String name, Supplier replacementFunction) { - this.name = name; - this.replacementFunction = replacementFunction; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getValue(A argument) { - return replacementFunction.get(); - } -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/Tag.java b/src/main/java/fr/xephi/authme/util/lazytags/Tag.java deleted file mode 100644 index 2c7c6ba5..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/Tag.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -/** - * Represents a tag in a text to be replaced with a value (which may depend on some argument). - * - * @param argument type the replacement may depend on - */ -public interface Tag { - - /** - * @return the tag to replace - */ - String getName(); - - /** - * Returns the value to replace the tag with for the given argument. - * - * @param argument the argument to evaluate the replacement for - * @return the replacement - */ - String getValue(A argument); -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/TagBuilder.java b/src/main/java/fr/xephi/authme/util/lazytags/TagBuilder.java deleted file mode 100644 index 677b30e2..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/TagBuilder.java +++ /dev/null @@ -1,21 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Utility class for creating tags. - */ -public final class TagBuilder { - - private TagBuilder() { - } - - public static Tag createTag(String name, Function replacementFunction) { - return new DependentTag<>(name, replacementFunction); - } - - public static Tag createTag(String name, Supplier replacementFunction) { - return new SimpleTag<>(name, replacementFunction); - } -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/TagReplacer.java b/src/main/java/fr/xephi/authme/util/lazytags/TagReplacer.java deleted file mode 100644 index a9d19319..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/TagReplacer.java +++ /dev/null @@ -1,102 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Replaces tags lazily by first determining which tags are being used - * and only applying those replacements afterwards. - * - * @param the argument type - */ -public final class TagReplacer { - - private final List> tags; - private final Collection messages; - - /** - * Private constructor. Use {@link #newReplacer(Collection, Collection)}. - * - * @param tags the tags that are being used in the messages - * @param messages the messages - */ - private TagReplacer(List> tags, Collection messages) { - this.tags = tags; - this.messages = messages; - } - - /** - * Creates a new instance of this class, which will provide the given - * messages adapted with the provided tags. - * - * @param allTags all available tags - * @param messages the messages to use - * @param the argument type - * @return new tag replacer instance - */ - public static TagReplacer newReplacer(Collection> allTags, Collection messages) { - List> usedTags = determineUsedTags(allTags, messages); - return new TagReplacer<>(usedTags, messages); - } - - /** - * Returns the messages with the tags applied for the given argument. - * - * @param argument the argument to get the messages for - * @return the adapted messages - */ - public List getAdaptedMessages(A argument) { - // Note ljacqu 20170121: Using a Map might seem more natural here but we avoid doing so for performance - // Although the performance gain here is probably minimal... - List tagValues = new LinkedList<>(); - for (Tag tag : tags) { - tagValues.add(new TagValue(tag.getName(), tag.getValue(argument))); - } - - List adaptedMessages = new LinkedList<>(); - for (String line : messages) { - String adaptedLine = line; - for (TagValue tagValue : tagValues) { - adaptedLine = adaptedLine.replace(tagValue.tag, tagValue.value); - } - adaptedMessages.add(adaptedLine); - } - return adaptedMessages; - } - - /** - * Determines which tags are used somewhere in the given list of messages. - * - * @param allTags all available tags - * @param messages the messages - * @param argument type - * @return tags used at least once - */ - private static List> determineUsedTags(Collection> allTags, Collection messages) { - return allTags.stream() - .filter(tag -> messages.stream().anyMatch(msg -> msg.contains(tag.getName()))) - .collect(Collectors.toList()); - } - - /** (Tag, value) pair. */ - private static final class TagValue { - - /** The tag to replace. */ - private final String tag; - /** The value to replace with. */ - private final String value; - - TagValue(String tag, String value) { - this.tag = tag; - this.value = value; - } - - @Override - public String toString() { - return "TagValue[tag='" + tag + "', value='" + value + "']"; - } - } - -} diff --git a/src/main/java/fr/xephi/authme/util/lazytags/WrappedTagReplacer.java b/src/main/java/fr/xephi/authme/util/lazytags/WrappedTagReplacer.java deleted file mode 100644 index ce9487e2..00000000 --- a/src/main/java/fr/xephi/authme/util/lazytags/WrappedTagReplacer.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.util.lazytags; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Applies tags lazily to the String property of an item. This class wraps - * a {@link TagReplacer} with the extraction of the String property and - * the creation of new items with the adapted string property. - * - * @param the item type - * @param the argument type to evaluate the replacements - */ -public class WrappedTagReplacer { - - private final Collection items; - private final BiFunction itemCreator; - private final TagReplacer tagReplacer; - - /** - * Constructor. - * - * @param allTags all available tags - * @param items the items to apply the replacements on - * @param stringGetter getter of the String property to adapt on the items - * @param itemCreator a function taking (T, String): the original item and the adapted String, returning a new item - */ - public WrappedTagReplacer(Collection> allTags, - Collection items, - Function stringGetter, - BiFunction itemCreator) { - this.items = items; - this.itemCreator = itemCreator; - - List stringItems = items.stream().map(stringGetter).collect(Collectors.toList()); - tagReplacer = TagReplacer.newReplacer(allTags, stringItems); - } - - /** - * Creates adapted items for the given argument. - * - * @param argument the argument to adapt the items for - * @return the adapted items - */ - public List getAdaptedItems(A argument) { - List adaptedStrings = tagReplacer.getAdaptedMessages(argument); - List adaptedItems = new LinkedList<>(); - - Iterator originalItemsIter = items.iterator(); - Iterator newStringsIter = adaptedStrings.iterator(); - while (originalItemsIter.hasNext() && newStringsIter.hasNext()) { - adaptedItems.add(itemCreator.apply(originalItemsIter.next(), newStringsIter.next())); - } - return adaptedItems; - } -} diff --git a/src/main/java/fr/xephi/authme/util/message/I18NUtils.java b/src/main/java/fr/xephi/authme/util/message/I18NUtils.java deleted file mode 100644 index da1d6769..00000000 --- a/src/main/java/fr/xephi/authme/util/message/I18NUtils.java +++ /dev/null @@ -1,102 +0,0 @@ -package fr.xephi.authme.util.message; - -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.properties.PluginSettings; -import fr.xephi.authme.util.Utils; -import org.bukkit.entity.Player; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -public class I18NUtils { - - private static Map PLAYER_LOCALE = new ConcurrentHashMap<>(); - private static final Map LOCALE_MAP = new HashMap<>(); - private static final List LOCALE_LIST = Arrays.asList( - "en", "bg", "de", "eo", "es", "et", "eu", "fi", "fr", "gl", "hu", "id", "it", "ja", "ko", "lt", "nl", "pl", - "pt", "ro", "ru", "sk", "sr", "tr", "uk" - ); - - static { - LOCALE_MAP.put("pt_br", "br"); - LOCALE_MAP.put("cs_cz", "cz"); - LOCALE_MAP.put("nds_de", "de"); - LOCALE_MAP.put("sxu", "de"); - LOCALE_MAP.put("swg", "de"); - LOCALE_MAP.put("rpr", "ru"); - LOCALE_MAP.put("sl_si", "si"); - LOCALE_MAP.put("vi_vn", "vn"); - LOCALE_MAP.put("lzh", "zhcn"); - LOCALE_MAP.put("zh_cn", "zhcn"); - LOCALE_MAP.put("zh_hk", "zhhk"); - LOCALE_MAP.put("zh_tw", "zhtw"); - //LOCALE_MAP.put("zhmc", "zhmc"); - } - - /** - * Returns the locale that player uses. - * - * @param player The player - */ - public static String getLocale(Player player) { - if (Utils.MAJOR_VERSION > 15) { - return player.getLocale().toLowerCase(); - } else if (PLAYER_LOCALE.containsKey(player.getUniqueId())) { - return PLAYER_LOCALE.get(player.getUniqueId()); - } - - return null; - } - - public static void addLocale(UUID uuid, String locale) { - if (PLAYER_LOCALE == null) { - PLAYER_LOCALE = new ConcurrentHashMap<>(); - } - - PLAYER_LOCALE.put(uuid, locale); - } - - public static void removeLocale(UUID uuid) { - PLAYER_LOCALE.remove(uuid); - } - - /** - * Returns the AuthMe messages file language code, by given locale and settings. - * Dreeam - Hard mapping, based on mc1.20.6, 5/29/2024 - * - * @param locale The locale that player client setting uses. - * @param settings The AuthMe settings, for default/fallback language usage. - */ - public static String localeToCode(String locale, Settings settings) { - // Certain locale code to AuthMe language code redirect - if (!settings.getProperty(PluginSettings.I18N_CODE_REDIRECT).isEmpty()) { - for (String raw : settings.getProperty(PluginSettings.I18N_CODE_REDIRECT)) { - String[] split = raw.split(":"); - - if (split.length == 2 && locale.equalsIgnoreCase(split[0])) { - return split[1]; - } - } - } - - // Match certain locale code - if (LOCALE_MAP.containsKey(locale)) { - return LOCALE_MAP.get(locale); - } - - if (locale.contains("_")) { - locale = locale.substring(0, locale.indexOf("_")); - } - - // Match locale code with "_" - if (LOCALE_LIST.contains(locale)) { - return locale; - } - - return settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); - } -} diff --git a/src/main/java/fr/xephi/authme/util/message/MiniMessageUtils.java b/src/main/java/fr/xephi/authme/util/message/MiniMessageUtils.java deleted file mode 100644 index 36756c62..00000000 --- a/src/main/java/fr/xephi/authme/util/message/MiniMessageUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.xephi.authme.util.message; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; - -public class MiniMessageUtils { - private static final MiniMessage miniMessage = MiniMessage.miniMessage(); - - /** - * Parse a MiniMessage string into a legacy string. - * - * @param message The message to parse. - * @return The parsed message. - */ - public static String parseMiniMessageToLegacy(String message) { - Component component = miniMessage.deserialize(message); - return LegacyComponentSerializer.legacyAmpersand().serialize(component); - } - private MiniMessageUtils() { - } -} diff --git a/src/main/resources/GeoLite2-Country.mmdb b/src/main/resources/GeoLite2-Country.mmdb deleted file mode 100644 index 9f580bdf..00000000 Binary files a/src/main/resources/GeoLite2-Country.mmdb and /dev/null differ diff --git a/src/main/resources/commands.yml b/src/main/resources/commands.yml deleted file mode 100644 index 0ba270d6..00000000 --- a/src/main/resources/commands.yml +++ /dev/null @@ -1,55 +0,0 @@ - -# This configuration file allows you to execute commands on various events. -# Supported placeholders in commands: -# %p is replaced with the player name. -# %nick is replaced with the player's nick name -# %ip is replaced with the player's IP address -# %country is replaced with the player's country -# -# For example, if you want to send a welcome message to a player who just registered: -# onRegister: -# welcome: -# command: 'msg %p Welcome to the server!' -# executor: CONSOLE -# -# This will make the console execute the msg command to the player. -# Each command under an event has a name you can choose freely (e.g. 'welcome' as above), -# after which a mandatory 'command' field defines the command to run, -# and 'executor' defines who will run the command (either PLAYER or CONSOLE). Longer example: -# onLogin: -# welcome: -# command: 'msg %p Welcome back!' -# executor: PLAYER -# broadcast: -# command: 'broadcast %p has joined, welcome back!' -# executor: CONSOLE -# -# You can also add delay to command. It will run after the specified ticks. Example: -# onLogin: -# rules: -# command: 'rules' -# executor: PLAYER -# delay: 200 -# -# Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, onUnregister -# -# For onLogin and onFirstLogin, you can use 'ifNumberOfAccountsLessThan' and 'ifNumberOfAccountsAtLeast' -# to specify limits to how many accounts a player can have (matched by IP) for a command to be run: -# onLogin: -# warnOnManyAccounts: -# command: 'say Uh oh! %p has many alt accounts!' -# executor: CONSOLE -# ifNumberOfAccountsAtLeast: 5 -# Commands to run for players logging in whose 'last login date' was empty -onFirstLogin: {} -onJoin: {} -onLogin: {} -# These commands are called whenever a logged in player uses /logout or quits. -# The commands are not run if a player that was not logged in quits the server. -# Note: if your server crashes, these commands won't be run, so don't rely on them to undo -# 'onLogin' commands that would be dangerous for non-logged in players to have! -onLogout: {} -onRegister: {} -onSessionLogin: {} -# Commands to run whenever a player is unregistered (by himself, or by an admin) -onUnregister: {} diff --git a/src/main/resources/email.html b/src/main/resources/email.html deleted file mode 100644 index 7b9e77fa..00000000 --- a/src/main/resources/email.html +++ /dev/null @@ -1,121 +0,0 @@ -

diff --git a/src/main/resources/messages/help_bg.yml b/src/main/resources/messages/help_bg.yml deleted file mode 100644 index e530a5aa..00000000 --- a/src/main/resources/messages/help_bg.yml +++ /dev/null @@ -1,335 +0,0 @@ -common: - header: ==========[ AuthMeReloaded - Помощ ]========== - optional: Опция - hasPermission: Имате права - noPermission: Нямате права - default: Стандартно - result: Резултат - defaultPermissions: - notAllowed: Не е разрешено - opOnly: Само за Оператори (OP) - allowed: Позволено за всички -section: - command: Команда - description: Кратко описание - detailedDescription: Подробно описание - arguments: Аргументи - alternatives: Алтернативи - permissions: Права - children: Команди -commands: - authme: - description: AuthMe op commands - detailedDescription: The main AuthMeReloaded command. The root for all admin commands. - authme.register: - description: Регистриране на играч - detailedDescription: Регистриране на играч с дадена парола. - arg1: - label: Играч - description: Име на играча - arg2: - label: парола - description: Парола - authme.unregister: - description: Премахване на регистрацията на играча - detailedDescription: Премахване на регистрацията на даден играч от базата данни. - arg1: - label: играч - description: име на играча - authme.forcelogin: - description: Удостоверяване на играча - detailedDescription: Удостоверяване на даденият играч. - arg1: - label: играч - description: име на играча - authme.password: - description: Промяна на парола - detailedDescription: Променя паролата на дадения играч. - arg1: - label: играч - description: име на играча - arg2: - label: парола - description: нова парола - authme.lastlogin: - description: Последен вход на играча - detailedDescription: Показва дата и час на последното влизане на дадения играч. - arg1: - label: играч - description: име на играча - authme.accounts: - description: Акаунти на играча - detailedDescription: Изброява всички акаунти на играча, според името и IP-адреса - arg1: - label: играч - description: име на играча или IP-адрес - authme.email: - description: Имейл адрес на играча - detailedDescription: Показва имейл адреса на посочения играч. - arg1: - label: играч - description: име на играча - authme.setemail: - description: Смяна на имейл на играча. - detailedDescription: Променя имейл адреса на дадения играч. - arg1: - label: играч - description: име на играча - arg2: - label: имейл - description: имейл на играча - authme.getip: - description: IP-адрес - detailedDescription: Показва текущият IP-адрес на посочения играч. - arg1: - label: играч - description: име на играча - authme.spawn: - description: Място на съживяване - detailedDescription: Телепортиране на мястото на съживяване. - authme.setspawn: - description: Задаване на място на съживяване. - detailedDescription: Задава точката на съживяване на текущото местонахождение. - authme.firstspawn: - description: Първоначално място на съживяване. - detailedDescription: Избира се първоначалното място на съживяване. - authme.setfirstspawn: - description: Задаване на първоначално място на съживяване. - detailedDescription: Задава първоначалната точка на съживяване на текущото местонахождение. - authme.purge: - description: Изтриване на стари данни. - detailedDescription: Изтрива стари данни според указаното количество дни. - arg1: - label: дни - description: брой дни - authme.purgeplayer: - description: Изтрива данните на даден играч. - detailedDescription: Изтрива всички данни на даден играч. - arg1: - label: Играч - description: Името на играча, за което трябва да се изтрият данните. - arg2: - label: Опции - description: '''force'' за да се изтрие без проверка дали играча е регистриран.' - authme.backup: - description: Създаване на резервно копие - detailedDescription: Създава резервно копие на всички регистрирани играчи. - authme.resetpos: - description: Рестартиране позиция на играч - detailedDescription: Рестартира последното известно местонахождение на указания - играч, или на всички играчи. - arg1: - label: играч|* - description: име на играча/всички играчи - authme.purgebannedplayers: - description: Изтриване на данни за блокирани играчи. - detailedDescription: Изтрива всички данни за блокираните играчи от базата данни. - authme.switchantibot: - description: Промяна на AntiBot-режима - detailedDescription: Променя режима на AntiBot системата според указанието. - arg1: - label: ON|OFF - description: включено/изключено - authme.reload: - description: Презареждане на плъгина. - detailedDescription: Презарежда плъгина AuthMeReloaded. - authme.version: - description: Информация за версията - detailedDescription: Показва подробна информация за версията на AuthMeReloaded, - неговите разработчици, помощници и лиценз. - authme.converter: - description: Преобразувател - detailedDescription: Преубразовател за базата данни. - arg1: - label: тип - description: 'тип преобразуване: xauth / crazylogin / rakamak / royalauth / - vauth / sqliteToSql / mysqlToSqlite' - authme.messages: - description: Добавяне на липсващи съобщения в помощния файл. - detailedDescription: Добавя всички стойности (на англ. език) в помощният файл. - authme.recent: - description: Проверка на скоро влизалите играчи. - detailedDescription: Показва последните играчи, които са били успешно влезли в играта. - authme.debug: - description: Отстраняване на грешки. - detailedDescription: Позволява различни опции за записване на грешки от плъгина. - arg1: - label: секция - description: Секцията за отстраняване на грешки, която да бъде изпълнена. - arg2: - label: аргумент - description: Аргумент (Зависи от избора на секция за отстраняване на грешки) - arg3: - label: аргумент - description: Аргумент (Зависи от избора на секция за отстраняване на грешки) - authme.help: - description: Помощ - detailedDescription: Показва помощ за командите започващи с /authme. - arg1: - label: команда - description: команда, за която е необходимо да се покаже помощ. - email: - description: Добавя имейл или възстановява парола. - detailedDescription: Основната команда на AuthMeReloaded свързана с имейлите. - email.show: - description: Показва Имейл - detailedDescription: Показва текущият Ви имейл. - email.add: - description: Добавяне на имейл. - detailedDescription: Добавя нов имейл адрес към Вашият акаунт. - arg1: - label: имейл - description: Имейл адрес - arg2: - label: Потвърждение - description: Потвърждение на имейл адреса. - email.change: - description: Смяна на Имейл - detailedDescription: Смяна на имейл адреса на Вашият акаунт. - arg1: - label: стар-имейл - description: Текущия имейл използван към Вашият акаунт - arg2: - label: нов-имейл - description: Новия имейл, който да бъде задеден към акаунта. - email.recover: - description: Възстановяване на парола чрез имейл. - detailedDescription: Възстановяване на Вашият акаунт, използвайки Имейл с нова парола. - arg1: - label: имейл - description: Имейл адреса на Вашият акаунт. - email.code: - description: Изпращане на код за възстановяване на парола. - detailedDescription: Възстановяване на Вашият акаунт чрез код, изпратен по имейл. - arg1: - label: код - description: Код за възстановяване - email.setpassword: - description: Задаване на нова парола след възстановяване. - detailedDescription: Задаване на нова парола след успешно възстановяване на Вашият акаунт. - arg1: - label: парола - description: Нова парола - email.help: - description: Помощ - detailedDescription: Подробна помощ за /email командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - login: - description: вход - detailedDescription: Командата която се използва за идентификация в сървъра на Вашият акаунт. - arg1: - label: парола - description: Паролата на акаунта Ви. - login.help: - description: Помощ - detailedDescription: Подробна помощ за /login командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - logout: - description: Изход - detailedDescription: Командата за изход от Вашият акаунт. - logout.help: - description: помощ - detailedDescription: КПодробна помощ за /logout командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - register: - description: Регистрация на акаунт. - detailedDescription: Команда за регистриране на Вашият акаунт. - arg1: - label: парола - description: Парола - arg2: - label: Потвърждение - description: Потвърждение на паролата - register.help: - description: Помощ - detailedDescription: Детайлна помощ за /register командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - unregister: - description: Дерегистриране на акаунт. - detailedDescription: Команда за премахване на регистрацията на Вашият акаунт. - arg1: - label: парола - description: Вашата парола. - unregister.help: - description: Помощ - detailedDescription: Детайлна помощ за /unregister командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - changepassword: - description: Смяна на парола - detailedDescription: Смяна на паролата за Вашият акаунт. - arg1: - label: текуща-парола - description: Текущата парола на Вашият акаунт. - arg2: - label: Нова парола - description: Новата парола, която да бъде използвана за Вашият акаунт. - changepassword.help: - description: Помощ - detailedDescription: Детайлна помощ за /changepassword командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - totp: - description: TOTP команди - detailedDescription: Команди свързани с допълнителната сигурност на акаунта Ви чрез секретен код. - totp.code: - description: Команда за вход - detailedDescription: Изпълнява проверката на секретния код на Вашият акаунт при влизане. - arg1: - label: код - description: Секретният код, използван за влизане. - totp.add: - description: Включване на TOTP - detailedDescription: Включване на защитата със секретен код за Вашият акаунт. - totp.confirm: - description: Активиране на TOTP след въвеждане на правилен секретен код. - detailedDescription: Запазва генерираният секретен код след потвърждение. - arg1: - label: код - description: Секретният код след изпълняване на командата /totp add - totp.remove: - description: Изключване на TOTP - detailedDescription: Изключване на защитата със секретен код за Вашият акаунт. - arg1: - label: код - description: Текущ секретен код - totp.help: - description: Помощ - detailedDescription: Детайлна помощ за /totp командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - captcha: - description: Код за сигурност - detailedDescription: Команда за код за сигурност. - arg1: - label: код - description: Код за сигурност - captcha.help: - description: Помощ - detailedDescription: Детайлна помощ за /captcha командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). - verification: - description: Команда за потвърждение. - detailedDescription: Команда за потвърждение. - arg1: - label: код - description: Код за потвърждение. - verification.help: - description: Помощ - detailedDescription: Детайлна помощ за /verification командите. - arg1: - label: команда - description: Командата за която да се покаже помощ (или за всички). diff --git a/src/main/resources/messages/help_br.yml b/src/main/resources/messages/help_br.yml deleted file mode 100644 index 818daf57..00000000 --- a/src/main/resources/messages/help_br.yml +++ /dev/null @@ -1,46 +0,0 @@ -# Arquivo de tradução da ajuda do AuthMe (comando /authme help) -# Tradução por Frani (PotterCraft_) e RenanYudi - -# ------------------------------------------------------- -# Lista de textos usados na seção de ajuda: -common: - header: '==========[ Ajuda AuthMeReloaded ]==========' - optional: 'Opcional' - hasPermission: 'Você tem permissão' - noPermission: 'Sem permissão' - default: 'Padrão' - result: 'Resultado' - defaultPermissions: - notAllowed: 'Sem permissão' - opOnly: 'Apenas jogadores com OP' - allowed: 'Todos tem permissão' - -# ------------------------------------------------------- -# Títulos das seções individuais de ajuda -# Deixe o texto traduzido vazio para desativá-lo/esconde-lo -# alternatives: '' -section: - command: 'Comando' - description: 'Descrição breve' - detailedDescription: 'Descrição detalhada' - arguments: 'Argumentos' - permissions: 'Permissões' - alternatives: 'Alternativas' - children: 'Comandos' - -# ------------------------------------------------------- -# Você pode traduzir o help de qualquer comando usando o padrão abaixo -# Por exemplo, para traduzir /authme reload, crie uma seção "authme.reload", ou "login" para /login -# Se o comando usa argumentos, você pode usar arg1 para traduzir o primeiro argumento e assim em diante, como exemplificado abaixo -# As traduções não precisam ser completas, qualquer parte faltante será obtida da configuração padrão. -# OBS: Coloque os comandos principais, como "authme" antes de seus subcomandos (como "authme.reload") -commands: - authme.register: - description: 'Registra um jogador' - detailedDescription: 'Registra um jogador específico com uma senha específica.' - arg1: - label: 'player' - description: 'Nome do jogador' - arg2: - label: 'password' - description: 'Senha' diff --git a/src/main/resources/messages/help_cz.yml b/src/main/resources/messages/help_cz.yml deleted file mode 100644 index 4d16d551..00000000 --- a/src/main/resources/messages/help_cz.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded HELP ]==========' - optional: 'Volitelné' - hasPermission: 'Máš oprávnění' - noPermission: 'Bez oprávnění' - default: 'Defaultní' - result: 'Výsledek' - defaultPermissions: - notAllowed: 'Bez oprávnění' - opOnly: 'Pouze OP' - allowed: 'Povolené pro všechny' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Příkaz' - description: 'Krátký popis' - detailedDescription: 'Detailní popis' - arguments: 'Argumenty' - permissions: 'Oprávnění' - alternatives: 'Alternativy' - children: 'Příkazy' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Registrovat hráče' - detailedDescription: 'Registrovat daného hráče s daným heslem.' - arg1: - label: 'hráč' - description: 'Jméno hráče' - arg2: - label: 'heslo' - description: 'Heslo' diff --git a/src/main/resources/messages/help_de.yml b/src/main/resources/messages/help_de.yml deleted file mode 100644 index b1841ef4..00000000 --- a/src/main/resources/messages/help_de.yml +++ /dev/null @@ -1,29 +0,0 @@ -common: - header: '==========[ AuthMeReloaded Hilfe ]==========' - optional: 'Optional' - hasPermission: 'Du hast Berechtigung' - noPermission: 'Keine Berechtigung' - default: 'Default' - result: 'Resultat' - defaultPermissions: - notAllowed: 'Kein Recht' - opOnly: 'Nur OP''s' - allowed: 'Allen erlaubt' -section: - command: 'Kommando' - description: 'Beschreibung' - detailedDescription: 'Detaillierte Beschreibung' - arguments: 'Argumente' - permissions: 'Rechte' - alternatives: 'Alternativen' - children: 'Kommandos' -commands: - authme.register: - description: 'Registriert einen Benutzer' - detailedDescription: 'Registriert den Benutzer mit dem gegebenen Passwort.' - arg1: - label: 'spieler' - description: 'Name des Spielers' - arg2: - label: 'passwort' - description: 'Passwort' diff --git a/src/main/resources/messages/help_en.yml b/src/main/resources/messages/help_en.yml deleted file mode 100644 index bcc501b7..00000000 --- a/src/main/resources/messages/help_en.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded HELP ]==========' - optional: 'Optional' - hasPermission: 'You have permission' - noPermission: 'No permission' - default: 'Default' - result: 'Result' - defaultPermissions: - notAllowed: 'No permission' - opOnly: 'OP''s only' - allowed: 'Everyone allowed' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Command' - description: 'Short description' - detailedDescription: 'Detailed description' - arguments: 'Arguments' - permissions: 'Permissions' - alternatives: 'Alternatives' - children: 'Commands' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Register a player' - detailedDescription: 'Register the specified player with the specified password.' - arg1: - label: 'player' - description: 'Player name' - arg2: - label: 'password' - description: 'Password' diff --git a/src/main/resources/messages/help_eo.yml b/src/main/resources/messages/help_eo.yml deleted file mode 100644 index ed9ba3fe..00000000 --- a/src/main/resources/messages/help_eo.yml +++ /dev/null @@ -1,31 +0,0 @@ -common: - header: '==========[ AuthMeReloaded Helpo ]==========' - optional: 'Laŭvola' - hasPermission: 'Vi havas permeson' - noPermission: 'Neniun permeson' - default: 'Apriora' - result: 'Rezulto' - defaultPermissions: - notAllowed: 'Neniun permeson' - opOnly: 'Nur el OP' - allowed: 'Ĉiu rajtas' - -section: - command: 'Komando' - description: 'Mallonga priskribo' - detailedDescription: 'Detala priskribo' - arguments: 'Argumentoj' - permissions: 'Permesoj' - alternatives: 'Alternativoj' - children: 'Komandoj' - -commands: - authme.register: - description: 'Registri ludanto' - detailedDescription: 'Registri la specifita ludanto kun la specifita pasvorton.' - arg1: - label: 'ludanto' - description: 'Ludanta nomo' - arg2: - label: 'pasvorto' - description: 'Pasvorto' diff --git a/src/main/resources/messages/help_es.yml b/src/main/resources/messages/help_es.yml deleted file mode 100644 index cddf5f70..00000000 --- a/src/main/resources/messages/help_es.yml +++ /dev/null @@ -1,294 +0,0 @@ -# Translated by MineSAT - -# ------------------------------------------------------- -# Lista de textos usados en la sección de ayuda. -common: - header: ======[ AYUDA de AuthMeReloaded ]====== - optional: Opcional - hasPermission: Tienes permiso - noPermission: No tienes permiso - default: Por defecto - result: Resultado - defaultPermissions: - notAllowed: No tienes permiso - opOnly: Sólamente OPeradores(Owner's) - allowed: Todo permitido -section: - command: Comando - description: Descripción corta - detailedDescription: Descripción detallada - arguments: Argumentos - alternatives: Alternativas - permissions: Permisos - children: Comandos -commands: - authme: - description: AuthMe comandos de OPerador - detailedDescription: El comando principal de AuthMeReloaded. La raíz de todos los comandos de administración. - authme.register: - description: Registrar un jugador - detailedDescription: Registra un jugador específico con una contraseña específica. - arg1: - label: jugador - description: Nombre del jugador - arg2: - label: contraseña - description: Contraseña del jugador - authme.unregister: - description: Cancelar cuenta de un jugador - detailedDescription: Elimina la cuenta registrada de un jugador. - arg1: - label: jugador - description: Nombre del jugador - authme.forcelogin: - description: Obliga el inicio de sesión - detailedDescription: Obliga a un jugador específico a iniciar sesión. - arg1: - label: jugador - description: Nombre del jugador en línea - authme.password: - description: Cambiar contraseña del jugador - detailedDescription: Cambia la contraseña de un jugador. - arg1: - label: jugador - description: Nombre del jugador - arg2: - label: contraseña - description: Nueva contraseña - authme.lastlogin: - description: Último inicio de sesión - detailedDescription: Ver la fecha del último inicio de sesión de un jugador específico. - arg1: - label: jugador - description: Nombre del jugador - authme.accounts: - description: Mostrar cuentas del jugador - detailedDescription: Muestra todas las cuentas de un jugador por su Nombre de Jugador o IP. - arg1: - label: jugador - description: Nombre del jugador o dirección IP - authme.email: - description: Mostrar correo del jugador - detailedDescription: Muestra el correo electrónico de un jugador específico, si este lo ha configurado en su cuenta. - arg1: - label: jugador - description: Nombre del jugador - authme.setemail: - description: Cambia el correo electrónico del jugador - detailedDescription: Cambia la dirección correo electrónico de un jugador especificado. - arg1: - label: jugador - description: Nombre del jugador - arg2: - label: email - description: Correo electrónico del jugador - authme.getip: - description: Obtiene la IP del jugador - detailedDescription: Obtiene la dirección IP de un jugador específico que esté en línea. - arg1: - label: jugador - description: Nombre del jugador - authme.spawn: - description: Teletransporte al Spawn - detailedDescription: Teletranspórtate al Spawn del servidor. - authme.setspawn: - description: Cambia el Spawn - detailedDescription: Cambia la zona de aparición del jugador por tu posición actual. - authme.firstspawn: - description: Teletransporte al primer Spawn - detailedDescription: Teletranspórtate a la primera zona de aparición del servidor. - authme.setfirstspawn: - description: Cambia el primer Spawn - detailedDescription: Cambia la primera zona de aparición del jugador por tu posición actual. - authme.purge: - description: Purgar(Limpiar) datos antiguos - detailedDescription: Purgar o Limpiar datos de AuthMeReloaded anteriores a el número días especificados en la configuración. - arg1: - label: días - description: Número de días - authme.purgeplayer: - description: Purgar los datos de un jugador - detailedDescription: Purgar los datos de un jugador seleccionado. - arg1: - label: jugador - description: El jugador para purgar o limpiar - arg2: - label: opciones - description: 'Escribe ''force'' al final del comando para forzar sin comprobar que el jugador está registrado' - authme.backup: - description: Realiza una copia de seguridad - detailedDescription: Crea una copia de seguridad de los usuarios registrados. - authme.resetpos: - description: Purgar o limpiar la última posición del jugador - detailedDescription: Purgar o limpiar la última posición conocida de un jugador específico o todos los jugadores. - arg1: - label: jugador / * - description: Nombre del jugador o escribe '*' para seleccionar todos los jugadores - authme.purgebannedplayers: - description: Purgar datos de jugadores baneados - detailedDescription: Purgar todos los datos de AuthMeReloaded de los jugadores baneados. - authme.switchantibot: - description: Cambiar el modo AntiBot - detailedDescription: Cambiar o alternar el modo AntiBot al estado especificado. - arg1: - label: modo - description: ON / OFF - authme.reload: - description: Recarga el plugin - detailedDescription: Recarga el plugin AuthMeReloaded. - authme.version: - description: Información de versión - detailedDescription: Muestra información detallada sobre la versión instalada de AuthMeReloaded, los creadores, contribuyentes, y la licencia. - authme.converter: - description: Comando conversor - detailedDescription: Comando conversor de AuthMeReloaded. - arg1: - label: trabajo - description: 'Trabajo de conversión: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite / loginsecurity' - authme.messages: - description: Añade mensajes faltantes - detailedDescription: Añade los mensajes que faltan al archivo de mensajes actual. - arg1: - label: help - description: Añade 'help' para actualizar to update the help messages file - authme.debug: - description: Funciones de depuración - detailedDescription: Permite varias operaciones de depuración. - arg1: - label: child - description: El hijo(child) a ejecutar - arg2: - label: arg - description: Argumento (depende de la sección de depuración) - arg3: - label: arg - description: Argumento (depende de la sección de depuración) - authme.help: - description: Muestra la ayuda - detailedDescription: Muestra detalladamente la ayuda para los comandos /authme. - arg1: - label: consulta - description: El comando o la consulta para ver su description. - email: - description: Añade el correo electrónico o recupera la contraseña - detailedDescription: La base del comando de correo electrónico de AuthMeReloaded. - email.show: - description: Mostrar correo electrónico - detailedDescription: Muestra you correo electrónico actual. - email.add: - description: Añadir correo electrónico - detailedDescription: Añade un nuevo correo electrónico a tu cuenta. - arg1: - label: email - description: Dirección de correo electrónico - arg2: - label: repiteEmail - description: Verificación de la dirección de correo electrónico - email.change: - description: Cambiar correo electrónico - detailedDescription: Cambia la dirección de correo electrónico de tu cuenta. - arg1: - label: anteriorEmail - description: Anterior dirección de correo electrónico - arg2: - label: nuevoEmail - description: Nueva dirección de correo electrónico - email.recover: - description: Recuperar contraseña usando el correo electrónico - detailedDescription: Recupera tu cuenta usando tu correo electrónico para enviarte una nueva contraseña. - arg1: - label: email - description: Dirección de correo electrónico - email.code: - description: Envía el código para recuperar tu contraseña - detailedDescription: Recupera tu cuenta enviando el código recibido en tu correo electrónico. - arg1: - label: código - description: Código de recuperación - email.setpassword: - description: Establece una nueva contraseña después de recuperar - detailedDescription: Establece una nueva contraseña después de recuperar completamente tu cuenta. - arg1: - label: contraseña - description: Nueva contraseña - email.help: - description: Muestra la ayuda - detailedDescription: Muestra detalladamente la ayuda de los comandos de /email. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - login: - description: Comando de inicio de sesión - detailedDescription: Comando para iniciar sesión utilizado en AuthMeReloaded. - arg1: - label: contraseña - description: Contraseña de inicio de sesión - login.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /login. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - logout: - description: Comando de cierre de sesión - detailedDescription: Comando de cierre de sesión usado por AuthMeReloaded. - logout.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /logout. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - register: - description: Registrar una cuenta - detailedDescription: Comando para registrar una cuenta usado por AuthMeReloaded. - arg1: - label: contraseña - description: Contraseña - arg2: - label: repiteContraseña - description: Repite la contraseña - register.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /register. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - unregister: - description: Eliminar registro de una cuenta - detailedDescription: Comando para eliminar una cuenta registrada usado por AuthMeReloaded. - arg1: - label: contraseña - description: Contraseña - unregister.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /unregister. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - changepassword: - description: Cambia la contraseña de una cuenta - detailedDescription: Comando para cambiar tu contraseña usado por AuthMeReloaded. - arg1: - label: antiguaContraseña - description: Antigua contraseña - arg2: - label: nuevaContraseña - description: Nueva contraseña - changepassword.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /changepassword. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. - captcha: - description: Comando del Captcha - detailedDescription: Comando del Captcha para AuthMeReloaded. - arg1: - label: captcha - description: El Captcha - captcha.help: - description: Mostrar la ayuda - detailedDescription: Mostrar la ayuda detallada del comando /captcha. - arg1: - label: consulta - description: El comando o consulta para ver la ayuda de este. diff --git a/src/main/resources/messages/help_et.yml b/src/main/resources/messages/help_et.yml deleted file mode 100644 index 03a70213..00000000 --- a/src/main/resources/messages/help_et.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded ABI ]==========' - optional: 'Valikuline' - hasPermission: 'Sul on luba' - noPermission: 'Pole luba' - default: 'Vaikimisi' - result: 'Tulemus' - defaultPermissions: - notAllowed: 'Pole luba' - opOnly: 'Ainult operaatorid' - allowed: 'Luba kõigil' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Käsklus' - description: 'Lühike kirjeldus' - detailedDescription: 'Detailne kirjeldus' - arguments: 'Argumendid' - permissions: 'Load' - alternatives: 'Alternatiivid' - children: 'Käsklused' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Registreeri mängija' - detailedDescription: 'Registreeri valitud mängija valitud parooliga.' - arg1: - label: 'mängija' - description: 'Mängija nimi' - arg2: - label: 'parool' - description: 'Parool' diff --git a/src/main/resources/messages/help_eu.yml b/src/main/resources/messages/help_eu.yml deleted file mode 100644 index 52fad802..00000000 --- a/src/main/resources/messages/help_eu.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded LAGUNTZA ]==========' - optional: 'Hautazkoa' - hasPermission: 'Baimena daukazu' - noPermission: 'Ez daukazu baimenik' - default: 'Lehenetsia' - result: 'Emaitza' - defaultPermissions: - notAllowed: 'Baimenik ez' - opOnly: 'OP bakarrik' - allowed: 'Edonor baimenduta' -section: - command: 'Komandoa' - description: 'Deskribapen laburra' - detailedDescription: 'Deskribapen xehakatua' - arguments: 'Argumentuak' - permissions: 'Baimenak' - alternatives: 'Alternatibak' - children: 'Komandoak' diff --git a/src/main/resources/messages/help_fr.yml b/src/main/resources/messages/help_fr.yml deleted file mode 100644 index dce54f16..00000000 --- a/src/main/resources/messages/help_fr.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Traduction des messages d'aide d'AuthMe (par exemple, pour les messages de "/authme help ()" ou de "/register help") - -# ------------------------------------------------------- -# Liste de texte dans les sections d'aide -common: - header: '==========[ AuthMe - AIDE & INFOS ]==========' - optional: 'Optionnel' - hasPermission: 'Vous avez la permission' - noPermission: 'Pas de permission' - default: 'Par défaut' - result: 'Résultat' - defaultPermissions: - notAllowed: 'Non permis' - opOnly: 'Seulement pour OP' - allowed: 'Tout le monde est permis' - -# ------------------------------------------------------- -# Nom individuel des sections d'aide -# Vous pouvez vider la zone de texte d'une section afin de la cacher, ex. pour cacher la section des alternatives: -# alternative(s): '' -section: - command: 'Commande' - description: 'Description' - detailedDescription: 'Description détaillée' - arguments: 'Argument(s)' - permissions: 'Permission' - alternatives: 'Alternative(s)' - children: 'Sous-commande(s)' - -# ------------------------------------------------------- -# Vous pouvez traduire tous les textes d'aide en utilisant la syntaxe ci-dessous. -# Par exemple, pour traduire l'aide du "/authme reload" créez une section nommée "authme.reload", ou "login" pour "/login". -# Si la commande a des arguments, vous pouvez utiliser "arg1" pour traduire le premier argument, "arg2" pour le 2ème, ainsi de suite. -# Les sections non traduites auront leur texte par défaut (en anglais), il n'est donc pas obligatoire de tout traduire. -# Important: Il faut mettre la commande principale (authme) avant sa sous-commande (ex. "authme.register" pour "/authme register") -commands: - authme.register: - description: 'Inscrire un pseudo' - detailedDescription: 'Inscrire un pseudo avec le mot de passe de votre choix' - arg1: - label: 'pseudo' - description: 'Pseudo du joueur à inscrire' - arg2: - label: 'mdp' - description: 'Mot de passe de connexion' diff --git a/src/main/resources/messages/help_hu.yml b/src/main/resources/messages/help_hu.yml deleted file mode 100644 index 93bfabd8..00000000 --- a/src/main/resources/messages/help_hu.yml +++ /dev/null @@ -1,351 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: ======[ AuthMeReloaded Segítség ]====== - optional: Opcionális - hasPermission: Van ehhez jogod - noPermission: Nincs jogod ehhez - default: Alapértelmezett - result: Eredmény - defaultPermissions: - notAllowed: Nincs jogod ehhez - opOnly: Op jog szükséges - allowed: Mindenkinek elérhető - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: Parancs - description: Rövid leírás - detailedDescription: Hosszabb leírás - arguments: Argumentum (változó) - permissions: Jogok - alternatives: Alternatívák - children: Parancsok - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme: - description: AuthMe operátor parancsok - detailedDescription: Az AuthMeReloaded fő parancsa. Az összes adminisztrációs parancs gyökere. - authme.register: - description: Játékos regisztrálása - detailedDescription: Megadott játékos regisztrálása egy megadott jelszóval. - arg1: - label: játékos - description: Játékos név - arg2: - label: jelszó - description: Jelszó - authme.unregister: - description: A játékos fiókjának visszavonása - detailedDescription: Kiveszi a játékos regisztrált fiókját. - arg1: - label: játékos - description: Játékos név - authme.forcelogin: - description: Kötelező bejelentkezés - detailedDescription: Ez arra kényszerít egy adott játékost, hogy jelentkezzen be. - arg1: - label: játékos - description: A játékos neve, ha online - authme.password: - description: A játékos jelszavának módosítása - detailedDescription: A játékos jelszavának módosítása. - arg1: - label: játékos - description: Játékos név - arg2: - label: jelszó - description: Új jelszó - authme.lastlogin: - description: Utolsó bejelentkezés - detailedDescription: Megtekintheti egy adott játékos utolsó bejelentkezésének dátumát. - arg1: - label: játékos - description: Játékos név - authme.accounts: - description: Játékosok megjelenítése - detailedDescription: Megmutassa a játékos összes fiókját a játékos nevével vagy IP-jével. - arg1: - label: játékos - description: Játékos neve vagy IP címe - authme.email: - description: Játékos levelek megjelenítése - detailedDescription: Egy adott játékos e-mailjét mutatja, ha a fiókjában beállította. - arg1: - label: játékos - description: Játékos név - authme.setemail: - description: Módosítsa a játékos e-mailjét - detailedDescription: Egy adott játékos e-mail címének módosítása. - arg1: - label: játékos - description: Játékos név - arg2: - label: email - description: A játékos e-mailje - authme.getip: - description: A játékos IP cím mutatása - detailedDescription: Kap egy adott online játékos IP-címét. - arg1: - label: játékos - description: Játékos név - authme.spawn: - description: Teleportálás a spawnra - detailedDescription: Teleportál a spawnra. - authme.setspawn: - description: Spawn beállítása - detailedDescription: Beállítja a spawn kezdőhelyet a játékos jelenlegi pozicíójában. - authme.firstspawn: - description: Teleportálás az első spawnhoz - detailedDescription: Teleportál az első spawn kezdőhelyre. - authme.setfirstspawn: - description: Első spawn beállítása - detailedDescription: Beállítja az első spawn kezdőhelyet a játékos jelenlegi pozicíójában. - authme.purge: - description: Törli a régi adatokat - detailedDescription: Törli az AuthMeReloaded játékos adatokat a megadott nap szerint. - arg1: - label: nap - description: Napok száma - authme.purgeplayer: - description: Játékos adat törlés - detailedDescription: Törli a kiválasztott játékos adatait. - arg1: - label: játékos - description: A játékos törlése az adatbázisból - arg2: - label: opciók - description: 'Írd be a parancs végén a ''force'' parancsot, hogy ellenőrizze a játékos regisztrálva van-e' - authme.backup: - description: Biztonsági másolat készítése - detailedDescription: Létrehoz egy biztonsági másolatot a regisztrált felhasználókról. - authme.resetpos: - description: Visszaállítja a játékos utolsó helyzetét - detailedDescription: Visszaállítja az adott játékos vagy az összes játékos utolsó ismert pozícióját. - arg1: - label: játékos - description: Játékos neve vagy írd be a '*' gomb az összes játékos kiválasztásához - authme.purgebannedplayers: - description: Törli az adatokat a kitiltott játékosoktól - detailedDescription: Törli az összes AuthMeReloaded adatokat a kitiltott játékosoktól. - authme.switchantibot: - description: Módosítja az AntiBot módot - detailedDescription: Az AntiBot mód megváltoztatása vagy átkapcsolása a megadott állapotra. - arg1: - label: mód - description: ON / OFF - authme.reload: - description: Plugin újratöltés - detailedDescription: Újratölti az AuthMeReloaded plugint. - authme.version: - description: Plugin verzió - detailedDescription: Részletes információ az AuthMeReloaded telepített verziójáról, az alkotókról, a közreműködőkről és az engedélyekről. - authme.converter: - description: Parancs konvertáló - detailedDescription: AuthMeReloaded konvertáló parancs. - arg1: - label: munka - description: 'Konverziós munka: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite / loginsecurity' - authme.messages: - description: Add hiányzó üzeneteket - detailedDescription: Hozzáadja a hiányzó üzeneteket az aktuális üzenetfájlhoz. - arg1: - label: help - description: A 'help' frissítéséhez, hogy frissítse a segítséget - authme.recent: - description: Utolsó bejelentkezett játékosok megjelenítése - detailedDescription: Megjeleníti az utolsó bejelentkezett játékosokat. - authme.debug: - description: Hibakeresés funkciói - detailedDescription: Lehetővé tesz több hibakeresési műveletet. - arg1: - label: gyermek - description: A végrehajtandó gyermek (gyermek) - arg2: - label: argumentum - description: Argumentum (a debug-szekciótól függ) - arg3: - label: argumentum - description: Argumentum (a debug-szekciótól függ) - authme.help: - description: Segítség megjelenítése - detailedDescription: Részletesen megmutatja az authme parancsok segítséget. - arg1: - label: konzultáció - description: A parancs vagy lekérdezés leírása. - email: - description: Hozzáadja az e-mailt vagy megjeleníti a játékos email-jét - detailedDescription: Az AuthMeReloaded e-mail parancs alapja. - email.show: - description: E-mail megjelenítése - detailedDescription: Jelenlegi e-mail megjelenítése. - email.add: - description: E-mail hozzáadása - detailedDescription: Új e-mail üzenet hozzáadása. - arg1: - label: email - description: E-mail cím - arg2: - label: emailMegerősítés - description: Az e-mail cím ellenőrzése - email.change: - description: E-mail megváltoztatása - detailedDescription: Megváltoztatja a fiók e-mail címét. - arg1: - label: RégiEmail - description: Korábbi e-mail cím - arg2: - label: újEmail - description: Új e-mail cím - email.recover: - description: Jelszó lekérése e-mail alapján - detailedDescription: Visszaszerezheted a fiókod e-mailben, hogy új jelszót küldjön. - arg1: - label: email - description: E-mail cím - email.code: - description: Kód elküldése a jelszó visszaállításához - detailedDescription: Visszaszerezheted a fiókod a kapott kód e-mailben történő elküldésével. - arg1: - label: kód - description: Helyreállítási kód - email.setpassword: - description: Jelszó beállítása - detailedDescription: Új jelszó beállítása a fiók teljes körű visszaállítása után. - arg1: - label: jelszó - description: Új jelszó - email.help: - description: E-mail segítség - detailedDescription: Részletes segítség az /email parancshoz. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lásd a segítséget. - login: - description: Bejelentkezés parancs - detailedDescription: Az AuthMeReloadedban használt bejelentkezési parancs. - arg1: - label: jelszó - description: Bejelentkezés jelszó - login.help: - description: Bejelentkezési segítség - detailedDescription: Részletes segítség a /login parancsról. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lásd a segítséget. - logout: - description: Kijelentkezés parancs - detailedDescription: Az AuthMeReloaded által használt kijelentkezés parancs. - logout.help: - description: Kijelentkezési segítség - detailedDescription: Részletes segítség a /logout parancsról. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lásd a segítséget. - register: - description: Fiók regisztrálása - detailedDescription: Parancs az AuthMeReloaded által használt fiók regisztrálásához. - arg1: - label: jelszó - description: Jelszó - arg2: - label: jelszóMegerősítő - description: Jelszó megerősítése - register.help: - description: Regisztrálási segítség - detailedDescription: Részletes segítség a /register parancsról. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lássuk a segítséget. - unregister: - description: Fiók törlése - detailedDescription: Parancs az AuthMeReloaded által használt regisztrált fiók törléséhez. - arg1: - label: jelszó - description: Jelszó - unregister.help: - description: Fiók törlési segítség - detailedDescription: Részletes segítség az /unregister parancsról. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lássuk a segítséget. - changepassword: - description: Fiók jelszó módosítása - detailedDescription: Parancs az AuthMeReloaded által használt jelszó megváltoztatásához. - arg1: - label: régiJelszó - description: Régi jelszó - arg2: - label: újJelszó - description: Új jelszó - changepassword.help: - description: Jelszó változtatási segítség - detailedDescription: Részletes segítség a /changepassword parancsról. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lássuk a segítséget. - totp: - description: Kétfaktoros hitelesítéssel kapcsolatos műveleteket végez - detailedDescription: Elvégzi a kétfaktoros hitelesítéssel kapcsolatos műveleteket. - totp.code: - description: Feldolgozza a kétfaktorú hitelesítési kódot bejelentkezés során - detailedDescription: A bejelentkezés során feldolgozza a kétfaktorú hitelesítési kódot. - arg1: - label: kód - description: Kód - totp.add: - description: Fiók kétütemű hitelesítése - detailedDescription: Engedélyezi a fiók kétütemű hitelesítését. - totp.confirm: - description: TOTP titkokat visszaigazolás után ment - detailedDescription: A létrehozott TOTP titkokat a visszaigazolás után elmenti. - arg1: - label: kód - description: Kód - totp.remove: - description: Fiók kétütemű hitelesítés letiltása - detailedDescription: Letiltja a fiók kétütemű hitelesítését. - arg1: - label: kód - description: Kód - totp.help: - description: /totp parancsok részletes segítsége - detailedDescription: Megtekinti a /totp parancsok részletes segítségét. - arg1: - label: kérdés - description: Kérdés - captcha: - description: Captcha parancs - detailedDescription: Captcha parancs az AuthMeReloaded számára. - arg1: - label: captcha - description: A captcha - captcha.help: - description: Segítség megjelenítése - detailedDescription: Megmutassa a /captcha parancs részletes segítségét. - arg1: - label: konzultáció - description: A parancs vagy a lekérdezés, hogy lásd a segítséget. - verification: - description: AuthMeReloaded hitelesítési folyamatának befejezése - detailedDescription: Parancs az AuthMeReloaded hitelesítési folyamatának befejezéséhez. - arg1: - label: kód - description: Kód - verification.help: - description: Részletes segítség a /verification parancshoz - detailedDescription: Részletes segítséget mutat a /verification parancshoz. - arg1: - label: kérdés - description: Kérdés diff --git a/src/main/resources/messages/help_it.yml b/src/main/resources/messages/help_it.yml deleted file mode 100644 index efa6d65b..00000000 --- a/src/main/resources/messages/help_it.yml +++ /dev/null @@ -1,151 +0,0 @@ -# Lingua Italiana creata da Maxetto e sgdc3. -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ Assistenza AuthMeReloaded ]==========' - optional: 'Opzionale' - hasPermission: 'Hai il permesso' - noPermission: 'Non hai il permesso' - default: 'Configurazione base' - result: 'Risultato' - defaultPermissions: - notAllowed: 'Nessuno autorizzato' - opOnly: 'Solo per OP' - allowed: 'Tutti autorizzati' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Comando' - description: 'Descrizione breve' - detailedDescription: 'Descrizione dettagliata' - arguments: 'Parametri' - permissions: 'Permessi' - alternatives: 'Alternative' - children: 'Comandi' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Registra un giocatore' - detailedDescription: 'Registra il giocatore indicato con la password inserita.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - arg2: - label: 'password' - description: 'Password' - authme.unregister: - description: 'Rimuovi un giocatore' - detailedDescription: 'Rimuovi il giocatore indicato dal Database.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - authme.forcelogin: - description: 'Forza l''autenticazione ad un giocatore' - detailedDescription: 'Autentica il giocatore indicato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore connesso' - authme.password: - description: 'Cambia la password di un giocatore' - detailedDescription: 'Cambia la password del giocatore indicato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - arg2: - label: 'password' - description: 'Nuova Password' - authme.lastlogin: - description: 'Ultima autenticazione di un giocatore' - detailedDescription: 'Visualizza l''ultima data di autenticazione del giocatore indicato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - authme.accounts: - description: 'Mostra i profili di un giocatore' - detailedDescription: 'Mostra tutti i profili di un giocatore attraverso il nome o l''indirizzo IP.' - arg1: - label: 'giocatore' - description: 'Nome o indirizzo IP del giocatore' - authme.email: - description: 'Mostra l''indirizzo email di un giocatore' - detailedDescription: 'Mostra l''indirizzo email del giocatore indicato se impostato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - authme.setemail: - description: 'Cambia l''indirizzo email di un giocatore' - detailedDescription: 'Cambia l''indirizzo email del giocatore indicato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore' - arg2: - label: 'email' - description: 'Indirizzo email del giocatore' - authme.getip: - description: 'Mostra l''indirizzo IP di un giocatore' - detailedDescription: 'Mostra l''indirizzo IP del giocatore indicato.' - arg1: - label: 'giocatore' - description: 'Nome del giocatore connesso' - authme.spawn: - description: 'Teletrasportati al punto di rigenerazione' - detailedDescription: 'Teletrasportati al punto di rigenerazione.' - authme.setspawn: - description: 'Cambia il punto di rigenerazione' - detailedDescription: 'Cambia il punto di rigenerazione dei giocatori alla tua posizione.' - authme.firstspawn: - description: 'Teletrasportati al punto di rigenerazione iniziale' - detailedDescription: 'Teletrasportati al punto di rigenerazione iniziale.' - authme.setfirstspawn: - description: 'Cambia il punto di rigenerazione iniziale' - detailedDescription: 'Cambia il punto di rigenerazione iniziale dei giocatori alla tua posizione.' - authme.purge: - description: 'Elimina i vecchi dati' - detailedDescription: 'Elimina i dati di AuthMeReloaded più vecchi dei giorni indicati.' - arg1: - label: 'giorni' - description: 'Numero di giorni' - authme.resetpos: - description: 'Elimina l''ultima posizione di un giocatore' - detailedDescription: 'Elimina l''ultima posizione conosciuta del giocatore indicato o di tutti i giocatori.' - arg1: - label: 'giocatore/*' - description: 'Nome del giocatore o ''*'' per tutti i giocatori' - authme.purgebannedplayers: - description: 'Elimina i dati dei giocatori banditi' - detailedDescription: 'Elimina tutti i dati di AuthMeReloaded dei giocatori banditi.' - authme.switchantibot: - description: 'Cambia lo stato del servizio di AntiBot' - detailedDescription: 'Cambia lo stato del servizio di AntiBot allo stato indicato.' - arg1: - label: 'stato' - description: 'ON / OFF' - authme.reload: - description: 'Ricarica il plugin' - detailedDescription: 'Ricarica il plugin AuthMeReloaded.' - authme.version: - description: 'Informazioni sulla versione' - detailedDescription: 'Mostra informazioni dettagliate riguardo la versione di AuthMeReloaded in uso, gli sviluppatori, i collaboratori e la licenza.' - authme.converter: - description: 'Comando per il convertitore' - detailedDescription: 'Comando per il convertitore di AuthMeReloaded.' - arg1: - label: 'incarico' - description: 'Incarico di conversione: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite' - authme.help: - description: 'Visualizza l''assistenza' - detailedDescription: 'Visualizza informazioni dettagliate per i comandi ''/authme''.' - arg1: - label: 'comando' - description: 'Il comando di cui vuoi ricevere assistenza' diff --git a/src/main/resources/messages/help_ja.yml b/src/main/resources/messages/help_ja.yml deleted file mode 100644 index 830275e4..00000000 --- a/src/main/resources/messages/help_ja.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded ヘルプ ]==========' - optional: 'オプション' - hasPermission: '権限を持っています' - noPermission: '権限がありません' - default: 'デフォルト' - result: '結果' - defaultPermissions: - notAllowed: '権限がありません' - opOnly: 'OPのみ' - allowed: '全員に許可' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'コマンド' - description: '簡単な説明' - detailedDescription: '詳細な説明' - arguments: '引数' - permissions: '権限' - alternatives: '代替' - children: 'コマンド' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'プレイヤーを登録します' - detailedDescription: '指定されたプレイヤーを指定されたパスワードで登録します。' - arg1: - label: 'プレイヤー名' - description: 'プレイヤー名' - arg2: - label: 'パスワード' - description: 'パスワード' diff --git a/src/main/resources/messages/help_ko.yml b/src/main/resources/messages/help_ko.yml deleted file mode 100644 index 561dc715..00000000 --- a/src/main/resources/messages/help_ko.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded 도움말 ]==========' - optional: '선택' - hasPermission: '권한이 있습니다' - noPermission: '권한이 없습니다' - default: 'Default' - result: 'Result' - defaultPermissions: - notAllowed: '권한이 없습니다' - opOnly: 'OP만 가능' - allowed: '모두에게 허용됨' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: '명령어' - description: '짧은 설명' - detailedDescription: '상세 설명' - arguments: '인수' - permissions: '권한' - alternatives: '대안' - children: '명령어' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: '플레이어 회원 가입' - detailedDescription: '지정한 플레이어를 지정한 비밀번호로 등록합니다.' - arg1: - label: '플레이어' - description: '플레이어 닉네임' - arg2: - label: '비밀번호' - description: '비밀번호' diff --git a/src/main/resources/messages/help_lt.yml b/src/main/resources/messages/help_lt.yml deleted file mode 100644 index ee141497..00000000 --- a/src/main/resources/messages/help_lt.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded PAGALBA ]==========' - optional: 'Neprivaloma' - hasPermission: 'Jūs turite leidimą' - noPermission: 'Jūs neturite leidimo' - default: 'Numatytas' - result: 'Rezultatas' - defaultPermissions: - notAllowed: 'Nėra leidimo' - opOnly: 'Tik OP' - allowed: 'Visiems leistina' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Komanda' - description: 'Trumpas aprašas' - detailedDescription: 'Detalus aprašas' - arguments: 'Argumentai' - permissions: 'Leidimai' - alternatives: 'Alternatyvos' - children: 'Komandos' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Užregistruoti žaidėją' - detailedDescription: 'Užregistruokite nurodytą žaidėją su nurodytu slaptažodžiu.' - arg1: - label: 'žaidėjas' - description: 'Žaidėjo vardas' - arg2: - label: 'slaptažodis' - description: 'Slaptažodis' diff --git a/src/main/resources/messages/help_nl.yml b/src/main/resources/messages/help_nl.yml deleted file mode 100644 index bf3cf3c9..00000000 --- a/src/main/resources/messages/help_nl.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Vertaling configuratie voor de help commando's in AuthMe, bijvoorbeeld bij het gebruik van /authme help of /authme help register - -# ------------------------------------------------------- -# Lijst van berichten zichtbaar in het help scherm -common: - header: '==========[ AuthMeReloaded HELP ]==========' - optional: 'Optioneel' - hasPermission: 'Je hebt rechten' - noPermission: 'Je hebt geen rechten' - default: 'Standaard' - result: 'Resultaat' - defaultPermissions: - notAllowed: 'Geen rechten' - opOnly: 'Alleen OP''s' - allowed: 'Iedereen is toegestaan' - -# ------------------------------------------------------- -# Titels van individuele help secties -# Stel de vertaling in als lege tekst om alternatieve commando's te verbergen: -# alternatives: '' -section: - command: 'Commando' - description: 'Korte beschrijving' - detailedDescription: 'Gedetailleerde beschrijving' - arguments: 'Argumenten' - permissions: 'Rechten' - alternatives: 'Alternatieven' - children: 'Commando''s' - -# ------------------------------------------------------- -# Je kunt de tekst voor alle commando's hieronder vertalen met het volgende patroon. -# Bijvoorbeeld: om /authme reload te vertalen, maak een sectie "authme.reload" aan, of "login" voor /login -# Als het commando argumenten/parameters bevat, kun je arg1 zoals hieronder vertalen, enzovoorts. -# Vertalingen hoeven niet compleet te zijn; missende secties zullen automatisch vanuit de standaard vertaling gehaald worden. -# Belangrijk: Plaats basis commando's zoals "authme" vóór hun sub-commando's (zoals "authme.reload") -commands: - authme.register: - description: 'Registreer een speler' - detailedDescription: 'Registreer de gespecificeerde speler met het opgegeven wachtwoord.' - arg1: - label: 'speler' - description: 'Naam speler' - arg2: - label: 'wachtwoord' - description: 'Wachtwoord' diff --git a/src/main/resources/messages/help_pl.yml b/src/main/resources/messages/help_pl.yml deleted file mode 100644 index a25326e8..00000000 --- a/src/main/resources/messages/help_pl.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Tlumaczenie configu dla AuthMe pomoc, kiedy wpiszesz /authme help lub /authme help register podana wiadomosc zostanie wyslana - -# ------------------------------------------------------- -# Lista tekstu uzyta w pomocy. -common: - header: '==========[ AuthMeReloaded - Pomoc ]==========' - optional: 'Opcjonalnie' - hasPermission: 'Posiadasz uprawnienia' - noPermission: 'Brak uprawnień' - default: 'Domyślnie' - result: 'Wynik' - defaultPermissions: - notAllowed: 'Nie posiadasz uprawnień' - opOnly: 'Tylko dla OP' - allowed: 'Dozwolone dla wszystkich' - -# ------------------------------------------------------- -# Tytuly z inwidualnych stref w pomoc. -# Zostaw tlumaczenie puste aby wylaczyc dana komende. Np.: -# alternatives: '' -section: - command: 'Komenda' - description: 'Opis' - detailedDescription: 'Szczegółowy opis' - arguments: 'Argumenty' - permissions: 'Uprawnienia' - alternatives: 'Aliasy' - children: 'Komendy' - -# ------------------------------------------------------- -# Mozesz przetlumaczyc wszystkie komendy uzywajac tego wzoru. -# Na przyklad jesli chcesz przetlumaczyc /authme reload, utworz selekcje "authme.reload", lub "login" dla /login -# Jesli komenda posiada argumenty, mozesz uzyc arg1 aby przetlumaczyc pierwszy argument, i nastepne -# Tlumaczenia nie musza byc kompletne; kazde braki beda uzupelniane domyslnymi wiadomosciami z pluginu. -# Uwaga: Postaw glowna klase (np. "authme") przed ich dziecmi (np. "authme.reload") -commands: - authme.register: - description: 'Rejestracja gracza' - detailedDescription: 'Rejestracja gracza z określonym hasłem' - arg1: - label: 'gracz' - description: 'Nazwa gracza' - arg2: - label: 'hasło' - description: 'Hasło gracza' diff --git a/src/main/resources/messages/help_pt.yml b/src/main/resources/messages/help_pt.yml deleted file mode 100644 index 2b2ead6c..00000000 --- a/src/main/resources/messages/help_pt.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AJUDA DO AuthMeReloaded ]==========' - optional: 'Opcional' - hasPermission: 'Tu tens permissão' - noPermission: 'Não tens permissão' - default: 'Padrão' - result: 'Resultado' - defaultPermissions: - notAllowed: 'Sem permissão' - opOnly: 'Só OP' - allowed: 'Toda gente é permitida' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Comando' - description: 'Breve descrição' - detailedDescription: 'Descrição detalhada' - arguments: 'Argumentos' - permissions: 'Permissões' - alternatives: 'Alternativas' - children: 'Comandos' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Registar um jogador' - detailedDescription: 'Registar um jogador com uma senha especifica.' - arg1: - label: 'jogador' - description: 'Nome de jogador' - arg2: - label: 'senha' - description: 'Senha' diff --git a/src/main/resources/messages/help_ro.yml b/src/main/resources/messages/help_ro.yml deleted file mode 100644 index 74e92c1f..00000000 --- a/src/main/resources/messages/help_ro.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded HELP ]==========' - optional: 'Optional' - hasPermission: 'Tu ai permisiunea' - noPermission: 'Fara permisiune' - default: 'Default' - result: 'Rezultat' - defaultPermissions: - notAllowed: 'Nu ai permisiune' - opOnly: 'Doar pentru operatori' - allowed: 'Toata lumea are acces' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Comanda' - description: 'Descriere scurta' - detailedDescription: 'Descriere detaliata' - arguments: 'Argumente' - permissions: 'Permisiuni' - alternatives: 'Alternative' - children: 'Comenzi' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Inregistreaza un jucator' - detailedDescription: 'Inregistreaza un jucator cu parola specificata.' - arg1: - label: 'jucator' - description: 'Numele jucatorului' - arg2: - label: 'parola' - description: 'Parola' diff --git a/src/main/resources/messages/help_ru.yml b/src/main/resources/messages/help_ru.yml deleted file mode 100644 index fff95815..00000000 --- a/src/main/resources/messages/help_ru.yml +++ /dev/null @@ -1,153 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ Помощь по AuthMeReloaded ]==========' - optional: 'необязательно' - hasPermission: 'есть' - noPermission: 'нет' - default: 'По умолчанию' - result: 'Право на использование' - defaultPermissions: - notAllowed: 'нет прав' - opOnly: 'только для операторов' - allowed: 'разрешено всем' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Команда' - description: 'Краткое описание' - detailedDescription: 'Описание' - arguments: 'Аргументы' - permissions: 'Права' - alternatives: 'Альтернативы' - children: 'Команды' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Регистрация игрока' - detailedDescription: 'Регистрирует игрока с указанным именем и паролем.' - arg1: - label: 'игрок' - description: 'имя игрока' - arg2: - label: 'пароль' - description: 'пароль' - authme.unregister: - description: 'Удаление регистрации игрока' - detailedDescription: 'Убирает регистрацию указанного игрока из базы данных.' - arg1: - label: 'игрок' - description: 'имя игрока' - authme.forcelogin: - description: 'Авторизация игрока' - detailedDescription: 'Авторизация указанного игрока.' - arg1: - label: 'игрок' - description: 'имя игрока в сети' - authme.password: - description: 'Изменение пароля игрока' - detailedDescription: 'Изменяет пароль указанного игрока.' - arg1: - label: 'игрок' - description: 'имя игрока' - arg2: - label: 'пароль' - description: 'новый пароль' - authme.lastlogin: - description: 'Последний вход игрока' - detailedDescription: 'Показывает дату и время последнего входа указанного игрока.' - arg1: - label: 'игрок' - description: 'имя игрока' - authme.accounts: - description: 'Учётные записи игрока' - detailedDescription: 'Отображает все учётные записи указанного игрока по его имени и IP-адресу.' - arg1: - label: 'игрок' - description: 'имя игрока или IP-адрес' - authme.email: - description: 'Электронная почта игрока' - detailedDescription: 'Отображает адрес электронной почты указанного игрока.' - arg1: - label: 'игрок' - description: 'имя игрока' - authme.setemail: - description: 'Смена эл. почты игрока' - detailedDescription: 'Изменяет адрес электронной почты указанного игрока.' - arg1: - label: 'игрок' - description: 'имя игрока' - arg2: - label: 'эл. почта' - description: 'электронная почта игрока' - authme.getip: - description: 'IP-адрес игрока' - detailedDescription: 'Показывает IP-адрес указанного игрока в сети.' - arg1: - label: 'игрок' - description: 'имя игрока' - authme.spawn: - description: 'Перемещение на точку возрождения' - detailedDescription: 'Перемещает на точку возрождения.' - authme.setspawn: - description: 'Перемещение точки возрождения' - detailedDescription: 'Перемещает точку возрождения игроков на ваше текущее местоположение.' - authme.firstspawn: - description: 'Перемещение на начальную точку появления' - detailedDescription: 'Перемещает на начальную точку появления.' - authme.setfirstspawn: - description: 'Перемещение начальной точки появления' - detailedDescription: 'Перемещает начальную точку появления игроков на ваше текущее местоположение.' - authme.purge: - description: 'Удаление старых данных' - detailedDescription: 'Удаляет старые данные старше указанного количества дней.' - arg1: - label: 'дни' - description: 'количество дней' - authme.resetpos: - description: 'Удаление последнего местоположения игрока' - detailedDescription: 'Удаляет последнее известное местоположение указанного игрока или всех игроков.' - arg1: - label: 'игрок|*' - description: 'имя игрока/все игроки' - authme.purgebannedplayers: - description: 'Удаление данных о заблокированных' - detailedDescription: 'Удаляет все данные о заблокированных игроках.' - authme.switchantibot: - description: 'Изменение AntiBot-режима' - detailedDescription: 'Изменяет AntiBot-режим на указанный.' - arg1: - label: 'ON|OFF' - description: 'включить/выключить' - authme.reload: - description: 'Перезагрузка плагина' - detailedDescription: 'Перезагружает плагин AuthMeReloaded.' - authme.version: - description: 'Информация о версии' - detailedDescription: 'Показывает подробную информацию об установленной версии AuthMeReloaded, его разработчиках, помощниках, а также о лицензии плагина.' - authme.converter: - description: 'Преобразователь' - detailedDescription: 'Преобразовывает базу данных.' - arg1: - label: 'тип' - description: 'тип преобразовывания: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite' - authme.help: - description: 'Просмотр помощи' - detailedDescription: 'Показывает помощь по командам /authme.' - arg1: - label: 'команда' - description: 'команда, для которой нужна помощь' - authme.backup: - description: 'Создание резервной копии' - detailedDescription: 'Создаёт резервную копию зарегистрированных пользователей.' diff --git a/src/main/resources/messages/help_si.yml b/src/main/resources/messages/help_si.yml deleted file mode 100644 index 207ec589..00000000 --- a/src/main/resources/messages/help_si.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded POMOČ ]==========' - optional: 'Neobvezno' - hasPermission: 'Imate dovoljenje' - noPermission: 'Nimate dovoljenja' - default: 'Prevzeto' - result: 'Rezultat' - defaultPermissions: - notAllowed: 'Nimate dovoljenja' - opOnly: 'Samo za OP' - allowed: 'Dovoljeno za vse' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Ukaz' - description: 'Krati opis' - detailedDescription: 'Natančen opis' - arguments: 'Argumenti' - permissions: 'Dovoljenja' - alternatives: 'Alternative' - children: 'Ukazi' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Register a player' - detailedDescription: 'Register the specified player with the specified password.' - arg1: - label: 'player' - description: 'Player name' - arg2: - label: 'password' - description: 'Password' diff --git a/src/main/resources/messages/help_sr.yml b/src/main/resources/messages/help_sr.yml deleted file mode 100644 index 144b9d9a..00000000 --- a/src/main/resources/messages/help_sr.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Konfiguracija za prevođenje pomoći AuthMe, primer kada kucate /authme help ili /authme help register - -# ------------------------------------------------------- -# Lista of teksta u pomoćnoj sekciji -common: - header: '==========[ AuthMeReloaded POMOĆ ]==========' - optional: 'Opcionalno' - hasPermission: 'Imate dozvola' - noPermission: 'Nemate dozvola' - default: 'Početan' - result: 'Rezultat' - defaultPermissions: - notAllowed: 'Nemate dozvola' - opOnly: 'Samo OP-ovi' - allowed: 'Dozvoljeno svima' - -# ------------------------------------------------------- -# Naslovi pojedinih sekcija pomoći -# Izbrišite deo teksta ako želite da iskjučite to, primer da sakrijte alternative: -# alternatives: '' -section: - command: 'Komanda' - description: 'Kratak opis' - detailedDescription: 'Detaljan opis' - arguments: 'Argumenti' - permissions: 'Dozvole' - alternatives: 'Alternative' - children: 'Komande' - -# ------------------------------------------------------- -# Možete prevesti podatke svih komandi koristeći uzorak ispod. -# Na primer da prevedete /authme reload, napravite sekciju "authme.reload", ili "login" za /login -# Ako komanda ima argumente, možete koristiti arg1 kao što je prikazano ispod za prvi argument, itd -# Prevodi ne moraju biti kompletni; sve sekcije koje nedostaju će biti uklonjene iz početnog tiho -# Važno: Postavite glavne komande kao što su "authme" pre njihovih sledbenika (primer "authme.reload") -commands: - authme.register: - description: 'Registrujte igrača' - detailedDescription: 'Registrujte specifičnog igrača specifičnom lozinkom.' - arg1: - label: 'igrač' - description: 'Ime igrača' - arg2: - label: 'lozinka' - description: 'Lozinka' diff --git a/src/main/resources/messages/help_vn.yml b/src/main/resources/messages/help_vn.yml deleted file mode 100644 index f63905ed..00000000 --- a/src/main/resources/messages/help_vn.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded Trợ giúp ]==========' - optional: 'Tùy chọn' - hasPermission: 'Bạn có quyền' - noPermission: 'Không có quyền' - default: 'Mặc định' - result: 'Kết quả' - defaultPermissions: - notAllowed: 'Không cho phép' - opOnly: 'Chỉ dành cho Op' - allowed: 'Dành cho mọi người' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: 'Lệnh' - description: 'Miêu tả ngắn' - detailedDescription: 'Miêu tả cụ thể' - arguments: 'Arguments' - permissions: 'Quyền hạn' - alternatives: 'Các lựa chọn khác' - children: 'Lệnh' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: 'Đăng ký người chơi' - detailedDescription: 'Đăng ký người chơi chỉ định với mật khẩu' - arg1: - label: 'player' - description: 'Tên của người chơi' - arg2: - label: 'password' - description: 'Mật khẩu' diff --git a/src/main/resources/messages/help_zhcn.yml b/src/main/resources/messages/help_zhcn.yml deleted file mode 100644 index c08add09..00000000 --- a/src/main/resources/messages/help_zhcn.yml +++ /dev/null @@ -1,204 +0,0 @@ -common: - header: '======================================' - optional: '可选' - hasPermission: '您拥有权限去使用这个指令' - noPermission: '您没有权限使用这个指令' - default: '默认' - result: '您的权限' - defaultPermissions: - notAllowed: '任何人不能使用' - opOnly: 'OP拥有此权限' - allowed: '所有人都可以使用' - - -section: - command: '指令' - description: '功能' - detailedDescription: '功能详情' - arguments: '参数' - permissions: '权限' - alternatives: '别名' - children: '子命令' - - -commands: - authme.register: - description: '注册一个玩家' - detailedDescription: '注册一个玩家' - arg1: - label: '玩家' - description: '玩家名称' - arg2: - label: '密码' - description: '密码' - authme.unregister: - description: '注销一个玩家' - detailedDescription: '注销一个玩家' - arg1: - label: '玩家' - description: '玩家' - authme.forcelogin: - description: '强制玩家重新登录' - detailedDescription: '强制使指定玩家重新登录' - arg1: - label: '玩家' - description: '玩家' - authme.password: - description: '改变某个玩家的密码' - detailedDescription: '改变某个玩家的密码' - arg1: - label: '玩家' - description: '玩家' - arg2: - label: '新密码' - description: '新密码' - authme.lastlogin: - description: '查看玩家最后登录时间' - detailedDescription: '查看玩家最后登录时间' - arg1: - label: '玩家' - description: '玩家' - authme.accounts: - description: '查看玩家IP下的账户' - detailedDescription: '查看玩家IP下的账户' - arg1: - label: '玩家或IP' - description: '玩家或IP' - authme.email: - description: '查看玩家的邮箱' - detailedDescription: '查看玩家的邮箱' - arg1: - label: '玩家' - description: '玩家' - authme.setemail: - description: '改变玩家的邮箱' - detailedDescription: '改变玩家的邮箱' - arg1: - label: '玩家' - description: '玩家' - arg2: - label: '邮箱' - description: '邮箱' - authme.getip: - description: '获取玩家IP' - detailedDescription: '获取玩家IP' - arg1: - label: '玩家' - description: '玩家' - authme.spawn: - description: '传送到AuthMe出生点' - detailedDescription: '传送到AuthMe出生点' - authme.setspawn: - description: '改变AuthMe出生点' - detailedDescription: '改变AuthMe出生点' - authme.firstspawn: - description: '传送到第一次进入游戏出生点' - detailedDescription: '传送到第一次进入游戏出生点' - authme.setfirstspawn: - description: '设置第一次进入游戏的出生点' - detailedDescription: '设置第一次进入游戏的出生点' - authme.purge: - description: '删除指定天数之前没登录的玩家登陆数据' - detailedDescription: '删除指定天数之前没登录的玩家登陆数据' - arg1: - label: '天数' - description: '天数' - authme.resetpos: - description: '重置玩家登出位置' - detailedDescription: '重置玩家登出位置' - arg1: - label: '玩家/*' - description: '玩家名称或所有玩家' - authme.purgebannedplayers: - description: '删除已经被封禁的玩家数据' - detailedDescription: '删除已经被封禁的玩家数据' - authme.switchantibot: - description: '改变AntiBot的状态' - detailedDescription: '改变AntiBot的状态' - arg1: - label: '开关' - description: '选项: ON/OFF' - authme.reload: - description: '重载插件' - detailedDescription: '重载插件' - authme.version: - description: '查看版本信息' - detailedDescription: '查看AuthmeReload版本,开发者,贡献者和许可' - authme.converter: - description: '转换数据命令' - detailedDescription: '转换数据命令' - arg1: - label: '类型' - description: '转换类型:xauth/crazylogin/rakamak/royalauth/vauth/sqliteToSql/mysqlToSqlite' - authme.messages: - description: '添加信息' - detailedDescription: '在语言文件夹中添加缺少的信息' - authme.help: - description: '查看帮助' - detailedDescription: '查看帮助' - arg1: - label: '子命令' - description: '查看的指令' - unregister: - description: '注销您的账户' - detailedDescription: '注销您的账户' - arg1: - label: '密码' - description: '密码' - changepassword: - description: '更改您的密码' - detailedDescription: '更改您的密码' - arg1: - label: '旧的密码' - description: '旧的密码' - arg2: - label: '新的密码' - description: '新的密码' - email: - description: '绑定邮箱或更改密码' - detailedDescription: '绑定邮箱或更改密码' - email.show: - description: '查看邮箱' - detailedDescription: '查看您的邮箱地址' - email.add: - description: '绑定邮箱' - detailedDescription: '为您的账户绑定邮箱' - arg1: - label: '邮箱' - description: '邮箱地址' - arg2: - label: '邮箱' - description: '重新输入邮箱地址' - email.change: - description: '改变邮箱地址' - detailedDescription: '更改您账户的邮箱地址' - arg1: - label: '旧邮箱' - description: '旧的邮箱地址' - arg2: - label: '新邮箱' - description: '新的邮箱地址' - email.recover: - description: '通过邮箱改变密码' - detailedDescription: '通过邮箱改变密码' - arg1: - label: '邮箱' - description: '邮箱地址' - email.help: - description: '查看帮助' - detailedDescription: '查看邮箱帮助' - arg1: - label: '子命令' - description: '指令' - captcha: - description: '验证码' - detailedDescription: '验证码' - arg1: - label: '验证码' - description: '验证码' - captcha.help: - description: '查看验证码帮助' - detailedDescription: '查看验证码帮助' - arg1: - label: '子命令' - description: '指令' diff --git a/src/main/resources/messages/help_zhhk.yml b/src/main/resources/messages/help_zhhk.yml deleted file mode 100644 index b3b4650a..00000000 --- a/src/main/resources/messages/help_zhhk.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ 登入系統指南 ]==========' - optional: '選填' - hasPermission: '你擁有此權限節點' - noPermission: '你並沒有此權限節點' - default: '預設權限' - result: '你的權限' - defaultPermissions: - notAllowed: '你並沒有此權限節點' - opOnly: '伺服器操作員限定' - allowed: '開放給所有玩家' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: '指令' - description: '簡述' - detailedDescription: '詳述' - arguments: '參數' - permissions: '權限' - alternatives: '替代指令' - children: '指令集' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: '登記一個新的玩家帳戶' - detailedDescription: '透過管理員身份,將一個玩家帳戶以指定的密碼註冊' - arg1: - label: 'player' - description: '玩家名稱' - arg2: - label: 'password' - description: '密碼' diff --git a/src/main/resources/messages/help_zhtw.yml b/src/main/resources/messages/help_zhtw.yml deleted file mode 100644 index 77eb6441..00000000 --- a/src/main/resources/messages/help_zhtw.yml +++ /dev/null @@ -1,349 +0,0 @@ -# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called - -# ------------------------------------------------------- -# List of texts used in the help section -common: - header: '==========[ AuthMeReloaded 幫助 ]==========' - optional: '選填' - hasPermission: '您有使用此指令的權限' - noPermission: '您沒有使用此指令的權限' - default: '預設' - result: '結果' - defaultPermissions: - notAllowed: '無權限' - opOnly: '僅限管理員' - allowed: '開放給所有人' - -# ------------------------------------------------------- -# Titles of the individual help sections -# Set the translation text to empty text to disable the section, e.g. to hide alternatives: -# alternatives: '' -section: - command: '指令' - description: '簡述' - detailedDescription: '詳述' - arguments: '參數' - permissions: '權限' - alternatives: '別名' - children: '指令集' - -# ------------------------------------------------------- -# You can translate the data for all commands using the below pattern. -# For example to translate /authme reload, create a section "authme.reload", or "login" for /login -# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth -# Translations don't need to be complete; any missing section will be taken from the default silently -# Important: Put main commands like "authme" before their children (e.g. "authme.reload") -commands: - authme.register: - description: '註冊一位玩家' - detailedDescription: '以指定的密碼註冊一位玩家。' - arg1: - label: '名稱' - description: '玩家名稱' - arg2: - label: '密碼' - description: '密碼' - authme.unregister: - description: '註銷一位玩家。' - detailedDescription: '註銷指定的玩家。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.forcelogin: - description: '強制玩家重新登入。' - detailedDescription: '強制指定的玩家重新登入。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.password: - description: '修改玩家的密碼。' - detailedDescription: '修改指定的玩家的密碼。' - arg1: - label: '名稱' - description: '玩家名稱' - arg2: - label: '密碼' - description: '密碼' - authme.lastlogin: - description: '查看玩家最後登入的日期。' - detailedDescription: '查看指定的玩家最後登入的日期。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.accounts: - description: '透過玩家名稱或 IP 顯示玩家的所有帳號。' - detailedDescription: '透過玩家名稱或 IP 顯示玩家的所有帳號。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.email: - description: '顯示指定的玩家的電子郵件地址。(如果有設置的話)' - detailedDescription: '顯示指定的玩家的電子郵件地址。(如果有設置的話)' - arg1: - label: '名稱' - description: '玩家名稱' - authme.setemail: - description: '修改玩家的電子郵件地址。' - detailedDescription: '修改指定的玩家的電子郵件地址。' - arg1: - label: '名稱' - description: '玩家名稱' - arg2: - label: '電子郵件地址' - description: '電子郵件地址' - authme.getip: - description: '取得線上玩家的 IP 位址。' - detailedDescription: '取得指定的線上玩家的 IP 位址。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.totp: - description: '顯示玩家是否開啟兩步驟驗證。' - detailedDescription: '顯示指定的玩家是否開啟兩步驟驗證。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.disabletotp: - description: '為玩家停用兩步驟驗證。' - detailedDescription: '為指定的玩家停用兩步驟驗證。' - arg1: - label: '名稱' - description: '玩家名稱' - authme.spawn: - description: '傳送至重生點。' - detailedDescription: '傳送至重生點。' - authme.setspawn: - description: '將玩家的重生點設為您現在的位置。' - detailedDescription: '將玩家的重生點設為您現在的位置。' - authme.firstspawn: - description: '傳送至新玩家重生點。' - detailedDescription: '傳送至新玩家重生點。' - authme.setfirstspawn: - description: '將新玩家的重生點設為您現在的位置。' - detailedDescription: '將新玩家的重生點設為您現在的位置。' - authme.purge: - description: '刪除超過指定天數的 AuthMeReloaded 資料。' - detailedDescription: '刪除超過指定天數的 AuthMeReloaded 資料。' - arg1: - label: '天' - description: '天數' - authme.purgeplayer: - description: '刪除玩家資料。' - detailedDescription: '刪除指定的玩家的資料。' - arg1: - label: '名稱' - description: '玩家名稱' - arg2: - label: '選項' - description: '選項' - authme.backup: - description: '備份玩家資料。' - detailedDescription: '備份所有玩家的資料。' - authme.resetpos: - description: '重設玩家的登出前位置。' - detailedDescription: '重設指定/所有玩家的登出前位置。' - arg1: - label: '名稱/*' - description: '指定玩家/所有玩家' - authme.purgebannedplayers: - description: '刪除已被封禁的玩家的資料。' - detailedDescription: '刪除所有已被封禁的玩家的資料。' - authme.switchantibot: - description: '切換 AntiBot 的模式。' - detailedDescription: '切換 AntiBot 的模式。' - arg1: - label: '模式' - description: '模式' - authme.reload: - description: '重新載入 AuthMeReloaded。' - detailedDescription: '重新載入 AuthMeReloaded。' - authme.version: - description: '顯示 AuthMeReloaded 的詳細資訊。' - detailedDescription: '顯示 AuthMeReloaded 的詳細資訊。例如版本、開發者、貢獻者、及授權。' - authme.converter: - description: 'AuthMeReloaded 的轉換器指令。' - detailedDescription: 'AuthMeReloaded 的轉換器指令。' - arg1: - label: '工作' - description: '工作' - authme.messages: - description: '修改目前的幫助檔案。' - detailedDescription: '修改目前的幫助檔案。' - authme.recent: - description: '顯示最近登入的玩家。' - detailedDescription: '顯示最近登入的玩家。' - authme.debug: - description: '除錯。' - detailedDescription: '除錯。' - arg1: - label: '子程序' - description: '子程序' - arg2: - label: '參數' - description: '參數' - arg3: - label: '參數' - description: '參數' - authme.help: - description: '顯示 /authme 指令的詳細介紹。' - detailedDescription: '顯示 /authme 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - email.show: - description: '顯示您目前的電子郵件地址。' - detailedDescription: '顯示您目前的電子郵件地址。' - email.add: - description: '新增電子郵件地址' - detailedDescription: '新增電子郵件地址至您的帳號。' - arg1: - label: '電子郵件地址' - description: '電子郵件地址' - arg2: - label: '確認電子郵件地址' - description: '確認電子郵件地址' - email.change: - description: '修改電子郵件地址' - detailedDescription: '修改您的帳號的電子郵件地址。' - arg1: - label: '舊的電子郵件地址' - description: '舊的電子郵件地址' - arg2: - label: '新的電子郵件地址' - description: '新的電子郵件地址' - email.recover: - description: '使用別的電子郵件地址復原您的帳號。' - detailedDescription: '復原您的帳號,將寄送新的密碼至您提供的電子郵件地址。' - arg1: - label: '電子郵件地址' - description: '電子郵件地址' - email.code: - description: '使用代碼復原您的帳號。' - detailedDescription: '輸入已寄送至您的電子郵件信箱的代碼以復原您的帳號。' - arg1: - label: '電子郵件地址' - description: '電子郵件地址' - email.setpassword: - description: '復原帳號後,設置新密碼。' - detailedDescription: '復原帳號後,設置新密碼。' - arg1: - label: '密碼' - description: '密碼' - email.help: - description: '顯示 /email 指令的詳細介紹。' - detailedDescription: '顯示 /email 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - login: - login.help: - description: '顯示 /login 指令的詳細介紹。' - detailedDescription: '顯示 /login 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - logout: - description: '登出帳號' - detailedDescription: '登出您的帳號。' - logout.help: - description: '顯示 /logout 指令的詳細介紹。' - detailedDescription: '顯示 /logout 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - register: - description: '註冊帳號' - detailedDescription: '註冊您的帳號。' - arg1: - label: '密碼' - description: '密碼' - arg2: - label: '確認密碼' - description: '確認密碼' - register.help: - description: '顯示 /register 指令的詳細介紹。' - detailedDescription: '顯示 /register 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - unregister: - description: '註銷帳號' - detailedDescription: '註銷您的帳號。' - arg1: - label: '密碼' - description: '密碼' - unregister.help: - description: '顯示 /unregister 指令的詳細介紹。' - detailedDescription: '顯示 /unregister 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - changepassword: - description: '修改密碼' - detailedDescription: '修改您的密碼。' - arg1: - label: '舊密碼' - description: '舊密碼' - arg2: - label: '新密碼' - description: '新密碼' - changepassword.help: - description: '顯示 /changepassword 指令的詳細介紹。' - detailedDescription: '顯示 /changepassword 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - totp: - description: '執行兩步驟驗證的相關操作。' - detailedDescription: '執行兩步驟驗證的相關操作。' - totp.code: - description: '登入時,輸入您的兩步驟驗證碼。' - detailedDescription: '登入時,輸入您的兩步驟驗證碼。' - arg1: - label: '驗證碼' - description: '驗證碼' - totp.add: - description: '為您的帳號啟用兩步驟驗證。' - detailedDescription: '為您的帳號啟用兩步驟驗證。' - totp.confirm: - description: '確認後,儲存生成的兩步驟驗證金鑰。' - detailedDescription: '確認後,儲存生成的兩步驟驗證金鑰。' - arg1: - label: '驗證碼' - description: '驗證碼' - totp.remove: - description: '為您的帳號停用兩步驟驗證。' - detailedDescription: '為您的帳號停用兩步驟驗證。' - arg1: - label: '驗證碼' - description: '驗證碼' - totp.help: - description: '顯示 /totp 指令的詳細介紹。' - detailedDescription: '顯示 /totp 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - captcha: - description: 'AuthMeReloaded 的 Captcha 指令。' - detailedDescription: 'AuthMeReloaded 的 Captcha 指令。' - arg1: - label: 'Captcha 碼' - description: 'Captcha 碼' - captcha.help: - description: '顯示 /captcha 指令的詳細介紹。' - detailedDescription: '顯示 /captcha 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' - verification: - description: '完成驗證過程的指令。' - detailedDescription: '完成驗證過程的指令。' - arg1: - label: '驗證碼' - description: '驗證碼' - verification.help: - description: '顯示 /verification 指令的詳細介紹。' - detailedDescription: '顯示 /verification 指令的詳細介紹。' - arg1: - label: '要查詢的指令' - description: '要查詢的指令' diff --git a/src/main/resources/messages/messages_bg.yml b/src/main/resources/messages/messages_bg.yml deleted file mode 100644 index 4b370bd9..00000000 --- a/src/main/resources/messages/messages_bg.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cРегистрациите са изключени!' - name_taken: '&cПотребителското име е заетo!' - register_request: '&3Моля регистрирайте се с: /register парола парола.' - command_usage: '&cКоманда: /register парола парола' - reg_only: '&4Само регистрирани потребители могат да влизат в сървъра! Моля посетете https://example.com, за да се регистрирате!' - success: '&2Успешна регистрация!' - kicked_admin_registered: 'Вие бяхте регистриран от администратора, моля да влезете отново!' - -# Password errors on registration -password: - match_error: '&cПаролите не съвпадат, провете ги отново!' - name_in_password: '&cНе можете да използвате потребителското си име за парола, моля изберете друга парола.' - unsafe_password: '&cИзбраната парола не е безопасна, моля изберете друга парола.' - forbidden_characters: '&4Паролата съдържа непозволени символи. Позволени символи: %valid_chars' - wrong_length: '&cПаролата е твърде къса или прекалено дълга! Моля опитайте с друга парола.' - pwned_password: '&cИзбраната парола не е сигурна. Тя е използвана %pwned_count пъти вече! Моля, използвайте силна парола...' - -# Login -login: - command_usage: '&cКоманда: /login парола' - wrong_password: '&cГрешна парола!' - success: '&2Успешен вход!' - login_request: '&cМоля влезте с: /login парола !' - timeout_error: '&4Времето за вход изтече, бяхте кикнат от сървъра. Моля опитайте отново!' - -# Errors -error: - denied_command: '&cЗа да използвате тази команда трябва да сте си влезли в акаунта!' - denied_chat: '&cЗа да пишете в чата трябва да сте си влезли в акаунта!' - unregistered_user: '&cПотребителското име не е регистрирано!' - not_logged_in: '&cНе сте влезли!' - no_permission: '&4Нямате нужните права за това действие!' - unexpected_error: '&4Получи се неочаквана грешка, моля свържете се с администратора!' - max_registration: '&cВие сте достигнали максималният брой регистрации (%reg_count/%max_acc %reg_names)!' - logged_in: '&cВече сте влезли!' - kick_for_vip: '&3VIP потребител влезе докато сървъра беше пълен, вие бяхте изгонен!' - kick_unresolved_hostname: '&cВъзникна грешка: неразрешено име на играч!' - tempban_max_logins: '&cВие бяхте баннат временно, понеже сте си сгрешили паролата прекалено много пъти.' - -# AntiBot -antibot: - kick_antibot: 'Защитата от ботове е включена! Трябва да изчакате няколко минути преди да влезете в сървъра.' - auto_enabled: '&4Защитата за ботове е включена заради потенциална атака!' - auto_disabled: '&2Защитата за ботове ще се изключи след %m минута/и!' - -# Unregister -unregister: - success: '&cРегистрацията е премахната успешно!' - command_usage: '&cКоманда: /unregister парола' - -# Other messages -misc: - account_not_activated: '&cВашият акаунт все още не е актириван, моля провете своят email адрес!' - not_activated: '&cАкаунтът не е активиран, моля регистрирайте се и го активирайте преди да опитате отново.' - password_changed: '&2Паротала е променена успешно!' - logout: '&2Излязохте успешно!' - reload: '&2Конфигурацията и база данните бяха презаредени правилно!' - usage_change_password: '&cКоманда: /changepassword Стара-Парола Нова-Парола' - accounts_owned_self: 'Притежавате %count акаунт/а:' - accounts_owned_other: 'Потребителят %name има %count акаунт/а:' - -# Session messages -session: - valid_session: '&2Сесията е продължена.' - invalid_session: '&cТвоят IP се е променил и сесията беше прекратена.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Вече има потребител със същото IP в сървъра!' - same_nick_online: '&4Вече има потребител, който играе в сървъра със същото потребителско име!' - name_length: '&4Потребителското име е прекалено късо или дълго. Моля опитайте с друго потребителско име!' - characters_in_name: '&4Потребителското име съдържа забранени знаци. Позволени знаци: %valid_chars' - kick_full_server: '&4Сървъра е пълен, моля опитайте отново!' - country_banned: '&4Твоята държава е забранена в този сървър!' - not_owner_error: 'Ти не си собственика на този акаунт. Моля избери друго потребителско име!' - invalid_name_case: 'Трябва да влезеш с %valid, а не с %invalid!' - quick_command: 'Използвате команди твърде бързо! Моля, влезте отново в сървъра и изчакайте малко преди да използвате команди.' - -# Email -email: - add_email_request: '&3Моля добавете имейл адрес към своят акаунт: /email add имейл имейл' - usage_email_add: '&cКоманда: /email add имейл имейл' - usage_email_change: '&cКоманда: /email change Стар-Имейл Нов-Имейл' - new_email_invalid: '&cНовият имейл е грешен, опитайте отново!' - old_email_invalid: '&cСтарият имейл е грешен, опитайте отново!' - invalid: '&cИмейла е невалиден, опитайте с друг!' - added: '&2Имейл адреса е добавен!' - add_not_allowed: '&cДобавянето на имейл не е разрешено!' - request_confirmation: '&cМоля потвърдете своя имейл адрес!' - changed: '&2Имейл адреса е сменен!' - change_not_allowed: '&cСмяната на имейл адреса не е разрешена!' - email_show: '&2Вашият имейл адрес е: &f%email' - no_email_for_account: '&2Няма добавен имейл адрес към акаунта.' - already_used: '&4Имейл адреса вече се използва, опитайте с друг.' - incomplete_settings: 'Грешка: Не всички настройки са написани за изпращане на имейл адрес. Моля свържете се с администратора!' - send_failure: 'Съобщението не беше изпратено. Моля свържете се с администратора.' - change_password_expired: 'Вече не е възможно да смените паролата си с тази команда.' - email_cooldown_error: '&cВече е бил изпратен имейл адрес. Трябва а изчакате %time преди да изпратите нов.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Забравена парола? Използвайте: /email recovery имейл' - command_usage: '&cКоманда: /email recovery имейл' - email_sent: '&2Възстановяващият имейл е изпратен успешно. Моля провете пощата си!' - code: - code_sent: 'Възстановяващият код беше изпратен на вашият email адрес.' - incorrect: 'Възстановяващият код е неправилен! Използвайте: /email recovery имейл, за да генерирате нов.' - tries_exceeded: 'Вие надвишихте максималният брой опити да въведете кода за възстановяване. Използвайте "/email recovery имейл" за да генерирате нов.' - correct: 'Кода за възстановяване е успешно въведен!' - change_password: 'Моля използвайте командата /email setpassword нова-парола за да смените Вашата парола веднага.' - -# Captcha -captcha: - usage_captcha: '&3Моля въведе цифрите/буквите от кода за сигурност: /captcha %captcha_code' - wrong_captcha: '&cКода е грешен, използвайте: "/captcha %captcha_code" в чата!' - valid_captcha: '&2Кода е валиден!' - captcha_for_registration: 'За да се регистрирате, трябва да въведете цифрите / буквите от кода за сигурност, използвайте командата: /captcha %captcha_code' - register_captcha_valid: '&2Кода е валиден! Вие вече може да се регистрирате с команда /register' - -# Verification code -verification: - code_required: '&3Тази команда е чувствителна и изисква потвърждение по имейл! Моля проверете си имейла и следвайте инструкциите в него.' - command_usage: '&cКоманда: /verification код' - incorrect_code: '&cНеправилен код, моля използвайте "/verification код" като използвате кода, който сте получили на Вашият имейл.' - success: '&2Вашата самоличност е потвърдена! Вие може да използвате всички команди в текущата Ви сесия!' - already_verified: '&2Вие вече можете да изпълнявате чувствителни команди в текущата Ви сесия!' - code_expired: '&3Вашият код е изтекъл. Изпълнете друга чувствителна команда за да генерирате нов код!' - email_needed: '&3За да потвърдите Вашата самоличност е необходимо да добавите имейл адрес към Вашият акаунт!!' - -# Time units -time: - second: 'секунда' - seconds: 'секунди' - minute: 'минута' - minutes: 'минути' - hour: 'час' - hours: 'часа' - day: 'ден' - days: 'дни' - -# Two-factor authentication -two_factor: - code_created: '&2Кода е %code. Можете да го проверите от тук: %url' - confirmation_required: 'Моля потвърдете Вашият код с команда /2fa confirm <код>' - code_required: 'Моля изпратете Вашият секретен код с команда /2fa code <код>' - already_enabled: 'Използването на секретен код е вече включено за Вашият акаунт!' - enable_error_no_code: 'Нямате добавен секретен код или кода е изтекъл. Моля изпълнете команда /2fa add' - enable_success: 'Успешно активирахте защита със секретен код за Вашият акаунт.' - enable_error_wrong_code: 'Грешен секретен код или е изтекъл. Моля изпълнете команда /2fa add' - not_enabled_error: 'Защитата със секретен код не е включена за Вашият акаунт. Моля изпълнете команда /2fa add' - removed_success: 'Успешно изключихте защитата със секретен код от Вашият акаунт!' - invalid_code: 'Невалиден код!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aУспешно автоматично влизане за Bedrock!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aЗаседнали сте в портал по време на влизане.' - fix_underground: '&aЗаседнали сте под земята по време на влизане.' - cannot_fix_underground: '&aЗаседнали сте под земята по време на влизане, но не можем да го поправим.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cБяхте изключени поради двойно влизане.' diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml deleted file mode 100644 index 396008bc..00000000 --- a/src/main/resources/messages/messages_br.yml +++ /dev/null @@ -1,176 +0,0 @@ -# AuthMe Reloaded | Tradução pt-br -# Por Eufranio, GabrielDev (DeathRush) e RenanYudi -# -# Lista de tags globais: -# %nl% - Pula uma linha -# %username% - Substitui pelo nome do jogador que está recebendo a mensagem -# %displayname% - Substitui pelo nickname (e cores) do jogador que está recebendo a mensagem - -# Registro -registration: - disabled: '&cRegistrar-se está desativado neste servidor!' - name_taken: '&cVocê já registrou este nome de usuário!' - register_request: '&3Por favor, registre-se com o comando "/register "' - command_usage: '&cUse: /register ' - reg_only: '&4Somente usuários registrados podem entrar no servidor! Por favor visite www.seusite.com para se registrar!' - success: '&2Registrado com sucesso!' - kicked_admin_registered: 'Um administrador registrou você. Por favor, faça login novamente' - -# Erros de senha ao registrar-se -password: - match_error: '&cAs senhas não coincidem, tente novamente!' - name_in_password: '&Você não pode usar o seu nome como senha. Por favor, escolha outra senha...' - unsafe_password: '&cA senha escolhida não é segura. Por favor, escolha outra senha...' - forbidden_characters: '&Sua senha contém caracteres inválidos. Caracteres permitidos: %valid_chars' - wrong_length: '&cSua senha é muito curta ou muito longa! Por favor, escolha outra senha...' - pwned_password: '&cSua senha escolhida não é segura. Ela foi usada %pwned_count vezes já! Por favor, use uma senha forte...' - -# Login -login: - command_usage: '&cUse: /login ' - wrong_password: '&cSenha incorreta!' - success: '&2Login realizado com sucesso!' - login_request: '&cPor favor, faça login com o comando "/login "' - timeout_error: '&4Tempo limite excedido.' - -# Erros -error: - denied_command: '&cPara utilizar este comando é necessário estar logado!' - denied_chat: '&cPara utilizar o chat é necessário estar logado!' - unregistered_user: '&cEste usuário não está registrado!' - not_logged_in: '&cVocê não está logado!' - no_permission: '&4Você não tem permissão para executar esta ação!' - unexpected_error: '&4Ocorreu um erro inesperado. Por favor contate um administrador!' - max_registration: '&cVocê excedeu o número máximo de registros (%reg_count/%max_acc %reg_names) para o seu IP!' - logged_in: '&cVocê já está logado!' - kick_for_vip: '&3Um jogador VIP juntou-se ao servidor enquanto ele estava cheio!' - kick_unresolved_hostname: '&cErro: hostname do jogador não resolvido!' - tempban_max_logins: '&cVocê foi temporariamente banido por tentar fazer login muitas vezes.' - -# AntiBot -antibot: - kick_antibot: 'O modo de proteção AntiBot está ativo, espere alguns minutos antes de entrar no servidor!' - auto_enabled: '&4O AntiBot foi ativado devido ao grande número de conexões!' - auto_disabled: '&2AntiBot desativado após %m minutos!' - -# Deletar conta -unregister: - success: '&cConta deletada!' - command_usage: '&cUse: /unregister ' - -# Outras mensagens -misc: - account_not_activated: '&cA sua conta ainda não está ativada. Por favor, verifique seus e-mails!' - not_activated: '&cConta não ativada, por favor registre e ative antes de tentar novamente.' - password_changed: '&2Senha alterada com sucesso!' - logout: '&2Desconectado com sucesso!' - reload: '&2A configuração e o banco de dados foram recarregados corretamente!' - usage_change_password: '&cUse: /changepassword ' - accounts_owned_self: 'Você tem %count contas:' - accounts_owned_other: 'O jogador %name tem %count contas:' - -# Mensagens de sessão -session: - valid_session: '&2Você deslogou recentemente, então sua sessão foi retomada!' - invalid_session: '&fO seu IP foi alterado e sua sessão expirou!' - -# Mensagens de erro ao entrar -on_join_validation: - same_ip_online: 'Um jogador com o mesmo IP já está no servidor!' - same_nick_online: '&4Alguém com o mesmo nome de usuário já está jogando no servidor!' - name_length: '&4Seu nome de usuário ou é muito curto ou é muito longo!' - characters_in_name: '&4Seu nome de usuário contém caracteres inválidos. Caracteres permitidos: %valid_chars' - kick_full_server: '&4O servidor está cheio, tente novamente mais tarde!' - country_banned: '&4O seu país está banido deste servidor!' - not_owner_error: 'Você não é o proprietário da conta. Por favor, escolha outro nome!' - invalid_name_case: 'Você deve entrar usando o nome de usuário %valid, não %invalid.' - quick_command: 'Você usou o comando muito rápido! Por favor, entre no servidor e aguarde antes de usar um comando novamente.' - -# E-mail -email: - add_email_request: '&3Por favor, adicione seu e-mail para a sua conta com o comando "/email add "' - usage_email_add: '&cUse: /email add ' - usage_email_change: '&cUse: /email change ' - new_email_invalid: '&cE-mail novo inválido, tente novamente!' - old_email_invalid: '&cE-mail antigo inválido, tente novamente!' - invalid: '&E-mail inválido, tente novamente!' - added: '&2E-mail adicionado com sucesso!' - add_not_allowed: '&cAdicionar um e-mail não é permitido.' - request_confirmation: '&cPor favor, confirme o seu endereço de e-mail!' - changed: '&2E-mail alterado com sucesso!' - change_not_allowed: '&cAlterar o e-mail não é permitido.' - email_show: '&2O seu endereço de e-mail atual é: &f%email' - no_email_for_account: '&2Você atualmente não têm endereço de e-mail associado a esta conta.' - already_used: '&4O endereço de e-mail já está sendo usado' - incomplete_settings: 'Erro: Nem todas as configurações necessárias estão definidas para o envio de e-mails. Entre em contato com um administrador.' - send_failure: '&cO e-mail não pôde ser enviado, reporte isso a um administrador!' - change_password_expired: 'Você não pode mais usar esse comando de recuperação de senha!' - email_cooldown_error: '&cUm e-mail já foi enviado, espere %time antes de enviar novamente!' - -# Recuperação de senha por e-mail -recovery: - forgot_password_hint: '&3Esqueceu a sua senha? Use o comando "/email recovery "' - command_usage: '&cUse: /email recovery ' - email_sent: '&2E-mail de recuperação enviado! Por favor, verifique sua caixa de entrada!' - code: - code_sent: 'Um código de recuperação para a redefinição de senha foi enviado ao seu e-mail.' - incorrect: 'Código de recuperação inválido! Você tem %count tentativas restantes.' - tries_exceeded: 'Você excedeu o limite de tentativas de usar o código de recuperação! Use "/email recovery [email]" para gerar um novo.' - correct: 'Código de recuperação aceito!' - change_password: 'Por favor, use o comando /email setpassword para alterar sua senha!' - -# Captcha -captcha: - usage_captcha: '&3Para iniciar sessão você tem que resolver um captcha, utilize o comando "/captcha %captcha_code"' - wrong_captcha: '&cCaptcha incorreto. Por favor, escreva "/captcha %captcha_code" no chat!' - valid_captcha: '&2Captcha correto!' - captcha_for_registration: 'Para se registrar você tem que resolver um código captcha, utilize o comando "/captcha %captcha_code"' - register_captcha_valid: '&2Captcha correto! Agora você pode se registrar usando /register !' - -# Código de verificação -verification: - code_required: '&3Esse comando é sensível e precisa de uma verificação via e-mail! Verifique sua caixa de entrada e siga as instruções do e-mail.' - command_usage: '&cUse: /verification ' - incorrect_code: '&cCódigo incorreto, utilize "/verification " com o código que você recebeu por e-mail!' - success: '&2Sua identidade foi verificada, agora você pode usar todos os comandos durante esta sessão.' - already_verified: '&2Você já pode executar comandos sensíveis durante esta sessão!' - code_expired: '&3O seu código expirou! Execute outro comando sensível para gerar um outro código.' - email_needed: '&3Para verificar sua identidade, você precisa vincular um e-mail à sua conta!' - -# Unidades de tempo -time: - second: 'segundo' - seconds: 'segundos' - minute: 'minuto' - minutes: 'minutos' - hour: 'hora' - hours: 'horas' - day: 'dia' - days: 'dias' - -# Verificação em duas etapas -two_factor: - code_created: '&2O seu código secreto é %code. Você pode verificá-lo aqui %url' - confirmation_required: 'Confirme seu código com /2fa confirm ' - code_required: 'Registre o seu código de verificação em duas etapas com /2fa code ' - already_enabled: 'A verificação em duas etapas já está ativada nesta conta!' - enable_error_no_code: 'Nenhuma chave de verificação foi gerada ou ela expirou. Por favor, use /2fa add' - enable_success: 'Verificação em duas etapas ativada com sucesso para esta conta!' - enable_error_wrong_code: 'Código incorreto ou expirado! Por favor, use /2fa add' - not_enabled_error: 'A verificação em duas etapas não está ativada nesta conta. Use /2fa add' - removed_success: 'Verificação em duas etapas desativada com sucesso!' - invalid_code: 'Código inválido!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aLogin automático Bedrock bem-sucedido!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aVocê está preso no portal durante o login.' - fix_underground: '&aVocê está preso no subsolo durante o login.' - cannot_fix_underground: '&aVocê está preso no subsolo durante o login, mas não podemos corrigir.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cVocê foi desconectado devido a login duplo.' diff --git a/src/main/resources/messages/messages_cz.yml b/src/main/resources/messages/messages_cz.yml deleted file mode 100644 index 4954457e..00000000 --- a/src/main/resources/messages/messages_cz.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegistrace je zakázána!' - name_taken: '&cUživatelské jméno je již zaregistrováno.' - register_request: '&cProsím, zaregistruj se pomocí "/register "' - command_usage: '&cPoužij: "/register heslo ZnovuHeslo".' - reg_only: '&cServer je pouze pro registrované! Navštiv naši webovou stránku https://priklad.cz.' - success: '&cRegistrace úspěšná!' - kicked_admin_registered: 'Admin vás právě zaregistroval; Přihlašte se prosím znovu.' - -# Password errors on registration -password: - match_error: '&cHesla se neshodují!' - name_in_password: '&cNemůžeš použít své jméno jako heslo, prosím, zvol si jiné heslo...' - unsafe_password: '&cToto heslo není bezpečné, prosím, zvol si jiné heslo...' - forbidden_characters: '&4Tvoje heslo obsahuje nepovolené znaky. Přípustné znaky jsou: %valid_chars' - wrong_length: '&cTvoje heslo nedosahuje minimální délky.' - pwned_password: '&cZvolené heslo není bezpečné. Bylo použito již %pwned_count krát! Prosím, použijte silné heslo...' - -# Login -login: - command_usage: '&cPoužij: "/login TvojeHeslo".' - wrong_password: '&cŠpatné heslo.' - success: '&cÚspěšně přihlášen!' - login_request: '&cProsím přihlaš se pomocí "/login TvojeHeslo".' - timeout_error: '&cČas pro přihlášení vypršel!' - -# Errors -error: - denied_command: '&cPokud chceš použít tento příkaz musíš být přihlášen/registrován!' - denied_chat: '&cNemůžeš psát do chatu dokuď se nepřihlásíš/nezaregistruješ!' - unregistered_user: '&cUživatelské jméno není zaregistrováno.' - not_logged_in: '&cNejsi přihlášený!' - no_permission: '&cNa tento příkaz nemáš dostatečné pravomoce.' - unexpected_error: '&cVyskytla se chyba - kontaktujte prosím administrátora ...' - max_registration: '&cPřekročil(a) jsi limit pro počet účtů (%reg_count/%max_acc %reg_names) z jedné IP adresy.' - logged_in: '&cJiž jsi přihlášen!' - kick_for_vip: '&cOmlouváme se, ale VIP hráč se připojil na plný server!' - kick_unresolved_hostname: '&cChyba: unresolved player hostname!' - tempban_max_logins: '&cByl jsi dočasně zabanován za příliš mnoho neúspěšných pokusů o přihlášení.' - -# AntiBot -antibot: - kick_antibot: 'Bezpečnostní mód AntiBot je zapnut! Musíš počkat několik minut než se budeš moct připojit znovu na server.' - auto_enabled: '[AuthMe] AntiBotMod automaticky spuštěn z důvodu mnoha souběžných připojení!' - auto_disabled: '[AuthMe] AntiBotMod automaticky ukončen po %m minutách, doufejme v konec invaze' - -# Unregister -unregister: - success: '&cÚspěšně odregistrován!' - command_usage: '&cPoužij: "/unregister TvojeHeslo".' - -# Other messages -misc: - account_not_activated: '&cTvůj účet ještě není aktivovaný, zkontroluj svůj E-mail.' - not_activated: '&cÚčet není aktivován, prosím zaregistrujte se a aktivujte ho před dalším pokusem.' - password_changed: '&cHeslo změněno!' - logout: '&cÚspěšně jsi se odhlásil.' - reload: '&cZnovu načtení nastavení AuthMe proběhlo úspěšně.' - usage_change_password: '&cPoužij: "/changepassword StaréHeslo NovéHeslo".' - accounts_owned_self: 'Vlastníš tyto účty (%count):' - accounts_owned_other: 'Hráč %name vlastní tyto účty (%count):' - -# Session messages -session: - valid_session: '&cAutomatické znovupřihlášení.' - invalid_session: '&cChyba: Počkej než vyprší tvoje relace.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Hráč se stejnou IP adresou nyní hraje na serveru!' - same_nick_online: '&cUživatel s tímto jménem již hraje na serveru.' - name_length: '&cTvůj nick je přílíš krátký, nebo přílíš dlouhý' - characters_in_name: '&cTvůj nick obsahuje nepovolené znaky. Přípustné znaky jsou: %valid_chars' - kick_full_server: '&cServer je momentálně plný, zkus to prosím později!' - country_banned: 'Připojení z tvé země je na tomto serveru zakázáno.' - not_owner_error: 'Nejsi majitelem tohoto účtu, prosím zvol si jiné jméno!' - invalid_name_case: 'Měl bys použít jméno %valid, ne jméno %invalid.' - quick_command: 'Použil jsi příkaz příliš rychle. Prosím, připoj se znovu a chvíli čekej před použitím dalšího příkazu.' - -# Email -email: - add_email_request: '&cPřidej prosím svůj email pomocí : /email add TvůjEmail TvůjEmail' - usage_email_add: '&fPoužij: /email add ' - usage_email_change: '&fPoužij: /email change ' - new_email_invalid: '[AuthMe] Nový email je chybně zadán!' - old_email_invalid: '[AuthMe] Starý email je chybně zadán!' - invalid: '[AuthMe] Nesprávný email' - added: '[AuthMe] Email přidán!' - add_not_allowed: '&cPřidávání emailu není povoleno!' - request_confirmation: '[AuthMe] Potvrď prosím svůj email!' - changed: '[AuthMe] Email změněn!' - change_not_allowed: '&cZměna emailu není povolena!' - email_show: '&2Tvůj aktuální email je: &f%email' - no_email_for_account: '&2K tomuto účtu nemáš přidanou žádnou emailovou adresu.' - already_used: '&4Tato emailová adresa je již používána' - incomplete_settings: 'Chyba: Chybí některé důležité informace pro odeslání emailu. Kontaktuj prosím admina.' - send_failure: 'Email nemohl být odeslán. Kontaktuj prosím admina.' - change_password_expired: 'Nemůžeš si změnit heslo pomocí toho příkazu.' - email_cooldown_error: '&cEmail už byl nedávno odeslán. Musíš čekat ještě %time před odesláním nového.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cZapomněl jsi heslo? Napiš: /email recovery ' - command_usage: '&fPoužij: /email recovery ' - email_sent: '[AuthMe] Email pro obnovení hesla odeslán!' - code: - code_sent: 'Kód pro obnovení hesla byl odeslán na váš email.' - incorrect: 'Obnovovací kód není správný! Počet zbývajících pokusů: %count.' - tries_exceeded: 'Překročil(a) jsi počet pokusů pro vložení kódu. Použij "/email recovery [email]" pro vygenerování nového' - correct: 'Obnovovací kód zadán správně!' - change_password: 'Prosím, použij příkaz /email setpassword pro změnu hesla okamžitě.' - -# Captcha -captcha: - usage_captcha: '&cPoužij: /captcha %captcha_code' - wrong_captcha: '&cŠpatné opsána Captcha, použij prosím: /captcha %captcha_code' - valid_captcha: '&cCaptcha je zadána v pořádku!' - captcha_for_registration: 'Před registrací je nutné správně opsat captchu. Prosím použij příkaz: /captcha %captcha_code' - register_captcha_valid: '&2Captcha je v pořádku! Nyní se můžeš zaregistrovat příkazem /register' - -# Verification code -verification: - code_required: '&3Tento příkaz vyžaduje ověření emailu! Zkontroluj svou mailovou schránku a postupuj dle instrukcí' - command_usage: '&cPoužití: /verification ' - incorrect_code: '&cNesprávný kód, prosím napiš "/verification " do chatu, místo použij kód co ti přišel emailem' - success: '&2Tvoje identita ověřena! V rámci své relace můžeš nyní používat všechny příkazy.' - already_verified: '&2Již můžeš používat příkazy ve své relaci bez omezení.' - code_expired: '&3Tvůj kód vypršel. Použij další citlivý příkaz pro získání nového kódu.' - email_needed: '&3Pro ověření tvé identity potřebujeme, abys ke svému účtu přidal svůj email.' - -# Time units -time: - second: 'sekundy' - seconds: 'sekund' - minute: 'minuty' - minutes: 'minut' - hour: 'hodiny' - hours: 'hodin' - day: 'dny' - days: 'dnu' - -# Two-factor authentication -two_factor: - code_created: '&2Tvůj tajný kód je %code. Můžeš ho oskenovat zde %url' - confirmation_required: 'Prosím, potvrď svůj kód příkazem /2fa confirm ' - code_required: 'Prosím, zadej kód dvoufaktorového ověření příkazem /2fa code ' - already_enabled: 'Dvoufaktorové ověření je již zapnuté pro tomto účtu.' - enable_error_no_code: 'Pro tvůj účet nebyl vygenerován žádný 2FA klíč, a nebo již vypršel. Prosím vygeneruj si ho pomocí /2fa add' - enable_success: 'Dvoufaktorové ověření bylo úspěšně nastaveno pro tvůj účet' - enable_error_wrong_code: 'Nesprávný kód, nebo kód vypršel. Prosím spusť příkaz /2fa add' - not_enabled_error: 'Dvoufaktorové ověření není zapnuté na tvém účtu. Můžeš ho zapnout použitím příkazu /2fa add' - removed_success: 'Dvoufaktorovka byla úspěšně odebrána z tvého účtu' - invalid_code: 'Nesprávný kód!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aAutomatické přihlášení Bedrock úspěšné!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aPři přihlášení jste uvízli v portálu.' - fix_underground: '&aPři přihlášení jste uvízli pod zemí.' - cannot_fix_underground: '&aPři přihlášení jste uvízli pod zemí, ale nemůžeme to opravit.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cByli jste odpojeni kvůli dvojímu přihlášení.' diff --git a/src/main/resources/messages/messages_de.yml b/src/main/resources/messages/messages_de.yml deleted file mode 100644 index 433e42a7..00000000 --- a/src/main/resources/messages/messages_de.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegistrierungen sind deaktiviert' - name_taken: '&cDieser Benutzername ist schon vergeben' - register_request: '&3Bitte registriere dich mit "/register "' - command_usage: '&cBenutze: /register ' - reg_only: '&4Nur für registrierte Spieler! Bitte besuche https://example.com um dich zu registrieren.' - success: '&2Erfolgreich registriert!' - kicked_admin_registered: 'Ein Administrator hat dich bereits registriert; bitte logge dich erneut ein.' - -# Password errors on registration -password: - match_error: '&cPasswörter stimmen nicht überein!' - name_in_password: '&cDu kannst deinen Namen nicht als Passwort verwenden!' - unsafe_password: '&cPasswort unsicher! Bitte wähle ein anderes.' - forbidden_characters: '&4Dein Passwort enthält unerlaubte Zeichen. Zulässige Zeichen: %valid_chars' - wrong_length: '&cDein Passwort ist zu kurz oder zu lang!' - pwned_password: '&cIhr gewähltes Passwort ist nicht sicher. Es wurde bereits %pwned_count Mal verwendet! Bitte verwenden Sie ein starkes Passwort...' - -# Login -login: - command_usage: '&cBenutze: /login ' - wrong_password: '&cFalsches Passwort' - success: '&2Successful login!' - login_request: '&cBitte logge dich ein mit "/login "' - timeout_error: '&4Zeitüberschreitung beim Login' - -# Errors -error: - denied_command: '&cUm diesen Befehl zu nutzen musst du authentifiziert sein!' - denied_chat: '&cDu musst eingeloggt sein, um chatten zu können!' - unregistered_user: '&cBenutzername nicht registriert!' - not_logged_in: '&cNicht eingeloggt!' - no_permission: '&4Du hast keine Rechte, um diese Aktion auszuführen!' - unexpected_error: '&4Ein Fehler ist aufgetreten. Bitte kontaktiere einen Administrator.' - max_registration: '&cDu hast die maximale Anzahl an Accounts erreicht (%reg_count/%max_acc %reg_names).' - logged_in: '&cBereits eingeloggt!' - kick_for_vip: '&3Ein VIP-Spieler hat den vollen Server betreten!' - kick_unresolved_hostname: '&cEin Fehler ist aufgetreten: nicht auflösbarer Spieler-Hostname!' - tempban_max_logins: '&cDu bist wegen zu vielen fehlgeschlagenen Login-Versuchen temporär gebannt!' - -# AntiBot -antibot: - kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du dich mit dem Server verbindest.' - auto_enabled: '&4[AntiBotService] AntiBotMod wurde aufgrund hoher Netzauslastung automatisch aktiviert!' - auto_disabled: '&2[AntiBotService] AntiBotMod wurde nach %m Minuten deaktiviert, hoffentlich ist die Invasion vorbei.' - -# Unregister -unregister: - success: '&cBenutzerkonto erfolgreich gelöscht!' - command_usage: '&cBenutze: /unregister ' - -# Other messages -misc: - account_not_activated: '&cDein Account wurde noch nicht aktiviert. Bitte prüfe deine E-Mails!' - not_activated: '&cKonto nicht aktiviert, bitte registrieren und aktivieren Sie es, bevor Sie es erneut versuchen.' - password_changed: '&2Passwort geändert!' - logout: '&2Erfolgreich ausgeloggt' - reload: '&2Konfiguration und Datenbank wurden erfolgreich neu geladen.' - usage_change_password: '&cBenutze: /changepassword ' - accounts_owned_self: 'Du besitzt %count Accounts:' - accounts_owned_other: 'Der Spieler %name hat %count Accounts:' - -# Session messages -session: - valid_session: '&2Erfolgreich eingeloggt!' - invalid_session: '&cUngültige Session. Bitte starte das Spiel neu oder warte, bis die Session abgelaufen ist.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Ein Spieler mit derselben IP ist bereits online!' - same_nick_online: '&4Jemand mit diesem Namen spielt bereits auf dem Server!' - name_length: '&4Dein Nickname ist zu kurz oder zu lang.' - characters_in_name: '&4Dein Nickname enthält unerlaubte Zeichen. Zulässige Zeichen: %valid_chars' - kick_full_server: '&4Der Server ist momentan voll, Sorry!' - country_banned: '&4Dein Land ist gesperrt!' - not_owner_error: 'Du bist nicht der Besitzer dieses Accounts. Bitte wähle einen anderen Namen!' - invalid_name_case: 'Dein registrierter Benutzername ist &2%valid&f - nicht &4%invalid&f.' - quick_command: 'Du hast einen Befehl zu schnell benutzt! Bitte trete dem Server erneut bei und warte, bevor du irgendeinen Befehl nutzt.' - -# Email -email: - add_email_request: '&3Bitte hinterlege deine E-Mail-Adresse: /email add ' - usage_email_add: '&cBenutze: /email add ' - usage_email_change: '&cBenutze: /email change ' - new_email_invalid: '&cDie neue E-Mail ist ungültig!' - old_email_invalid: '&cDie alte E-Mail ist ungültig!' - invalid: '&cUngültige E-Mail!' - added: '&2E-Mail hinzugefügt!' - add_not_allowed: '&cHinzufügen einer E-Mail nicht gestattet!' - request_confirmation: '&cBitte bestätige deine E-Mail!' - changed: '&2E-Mail aktualisiert!' - change_not_allowed: '&cBearbeiten einer E-Mail nicht gestattet!' - email_show: '&2Deine aktuelle E-Mail-Adresse ist: &f%email' - no_email_for_account: '&2Du hast zur Zeit keine E-Mail-Adresse für deinen Account hinterlegt.' - already_used: '&4Diese E-Mail-Adresse wird bereits genutzt.' - incomplete_settings: 'Fehler: Es wurden nicht alle notwendigen Einstellungen vorgenommen, um E-Mails zu senden. Bitte kontaktiere einen Administrator.' - send_failure: 'Die E-Mail konnte nicht gesendet werden. Bitte kontaktiere einen Administrator.' - change_password_expired: 'Mit diesem Befehl kannst du dein Passwort nicht mehr ändern.' - email_cooldown_error: '&cEine E-Mail wurde erst kürzlich versendet. Du musst %time warten, bevor du eine neue anfordern kannst.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Passwort vergessen? Nutze "/email recovery " für ein neues Passwort' - command_usage: '&cBenutze: /email recovery ' - email_sent: '&2Wiederherstellungs-E-Mail wurde gesendet!' - code: - code_sent: 'Ein Wiederherstellungscode zum Zurücksetzen deines Passworts wurde an deine E-Mail-Adresse geschickt.' - incorrect: 'Der Wiederherstellungscode stimmt nicht! Du hast noch %count Versuche. Nutze /email recovery [email] um einen neuen zu generieren.' - tries_exceeded: 'Du hast die maximale Anzahl an Versuchen zur Eingabe des Wiederherstellungscodes überschritten. Benutze "/email recovery [email]" um einen neuen zu generieren.' - correct: 'Der eingegebene Wiederherstellungscode ist richtig!' - change_password: 'Benutze bitte den Befehl /email setpassword um dein Passwort umgehend zu ändern.' - -# Captcha -captcha: - usage_captcha: '&3Um dich einzuloggen, tippe dieses Captcha so ein: /captcha %captcha_code' - wrong_captcha: '&cFalsches Captcha, bitte nutze: /captcha %captcha_code' - valid_captcha: '&2Das Captcha ist korrekt!' - captcha_for_registration: 'Um dich zu registrieren, musst du erst ein Captcha lösen, bitte nutze den Befehl: /captcha %captcha_code' - register_captcha_valid: '&2Captcha richtig! Du kannst dich jetzt registrieren mit: /register' - -# Verification code -verification: - code_required: '&3Dieser Befehl ist sensibel und erfordert eine E-Mail-Verifizierung! Überprüfe deinen Posteingang und folge den Anweisungen der E-Mail.' - command_usage: '&cBenutze: /verification ' - incorrect_code: '&Falscher Code, bitte gib "/verification " in den Chat ein, und verwende den Code, den Du per E-Mail erhalten hast.' - success: '&2Deine Identität wurde verifiziert! Du kannst nun alle Befehle innerhalb der aktuellen Sitzung ausführen!' - already_verified: '&2Du kannst bereits jeden sensiblen Befehl innerhalb der aktuellen Sitzung ausführen!' - code_expired: '&3Dein Code ist abgelaufen! Führe einen weiteren sensiblen Befehl aus, um einen neuen Code zu erhalten!' - email_needed: '&3Um deine Identität zu überprüfen, musst Du eine E-Mail-Adresse mit deinem Konto verknüpfen!' - -# Time units -time: - second: 'Sekunde' - seconds: 'Sekunden' - minute: 'Minute' - minutes: 'Minuten' - hour: 'Stunde' - hours: 'Stunden' - day: 'Tag' - days: 'Tage' - -# Two-factor authentication -two_factor: - code_created: '&2Dein geheimer Code ist %code. Du kannst ihn hier abfragen: %url' - confirmation_required: 'Bitte bestätige deinen Code mit /2fa confirm ' - code_required: 'Bitte übermittle deinen Zwei-Faktor-Authentifizierungscode mit /2fa code ' - already_enabled: 'Die Zwei-Faktor-Authentifizierung ist für dein Konto bereits aktiviert!' - enable_error_no_code: 'Es wurde kein 2FA-Schlüssel für dich generiert oder er ist abgelaufen. Bitte nutze /2fa add' - enable_success: 'Zwei-Faktor-Authentifizierung für dein Konto erfolgreich aktiviert' - enable_error_wrong_code: 'Code falsch oder abgelaufen. Bitte nutze /2fa add' - not_enabled_error: 'Die Zwei-Faktor-Authentifizierung ist für dein Konto nicht aktiviert. Benutze /2fa add' - removed_success: 'Die Zwei-Faktor-Authentifizierung wurde erfolgreich von deinem Konto entfernt' - invalid_code: 'Ungültiger Code!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock Auto-Login erfolgreich!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aSie stecken während des Logins im Portal fest.' - fix_underground: '&aSie stecken während des Logins unter der Erde fest.' - cannot_fix_underground: '&aSie stecken während des Logins unter der Erde fest, aber wir können es nicht beheben.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cSie wurden wegen doppeltem Login getrennt.' diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml deleted file mode 100644 index 40ed034b..00000000 --- a/src/main/resources/messages/messages_en.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cIn-game registration is disabled!' - name_taken: '&cYou already have registered this username!' - register_request: '&3Please, register to the server with the command: /register ' - command_usage: '&cUsage: /register ' - reg_only: '&4Only registered users can join the server! Please visit https://example.com to register yourself!' - success: '&2Successfully registered!' - kicked_admin_registered: 'An admin just registered you; please log in again.' - -# Password errors on registration -password: - match_error: '&cPasswords didn''t match, check them again!' - name_in_password: '&cYou can''t use your name as password, please choose another one...' - unsafe_password: '&cThe chosen password isn''t safe, please choose another one...' - forbidden_characters: '&4Your password contains illegal characters. Allowed chars: %valid_chars' - wrong_length: '&cYour password is too short or too long! Please try with another one!' - pwned_password: '&cYour chosen password is not secure. It was used %pwned_count times already! Please use a strong password...' - -# Login -login: - command_usage: '&cUsage: /login ' - wrong_password: '&cWrong password!' - success: '&2Successful login!' - login_request: '&cPlease, login with the command: /login ' - timeout_error: '&4Login timeout exceeded, you have been kicked from the server, please try again!' - -# Errors -error: - denied_command: '&cIn order to use this command you must be authenticated!' - denied_chat: '&cIn order to chat you must be authenticated!' - unregistered_user: '&cThis user isn''t registered!' - not_logged_in: '&cYou''re not logged in!' - no_permission: '&4You don''t have the permission to perform this action!' - unexpected_error: '&4An unexpected error occurred, please contact an administrator!' - max_registration: '&cYou have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection!' - logged_in: '&cYou''re already logged in!' - kick_for_vip: '&3A VIP player has joined the server when it was full!' - kick_unresolved_hostname: '&cAn error occurred: unresolved player hostname!' - tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' - auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' - auto_disabled: '&2[AntiBotService] AntiBot disabled after %m minutes!' - -# Unregister -unregister: - success: '&cSuccessfully unregistered!' - command_usage: '&cUsage: /unregister ' - -# Other messages -misc: - account_not_activated: '&cYour account isn''t activated yet, please check your emails!' - not_activated: '&cAccount not activated, please register and activate it before trying again.' - password_changed: '&2Password changed successfully!' - logout: '&2Logged out successfully!' - reload: '&2Configuration and database have been reloaded correctly!' - usage_change_password: '&cUsage: /changepassword ' - accounts_owned_self: 'You own %count accounts:' - accounts_owned_other: 'The player %name has %count accounts:' - -# Session messages -session: - invalid_session: '&cYour IP has been changed and your session data has expired!' - valid_session: '&2Logged-in due to Session Reconnection.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'A player with the same IP is already in game!' - same_nick_online: '&4The same username is already playing on the server!' - name_length: '&4Your username is either too short or too long!' - characters_in_name: '&4Your username contains illegal characters. Allowed chars: %valid_chars' - kick_full_server: '&4The server is full, try again later!' - country_banned: '&4Your country is banned from this server!' - not_owner_error: 'You are not the owner of this account. Please choose another name!' - invalid_name_case: 'You should join using username %valid, not %invalid.' - quick_command: 'You used a command too fast! Please, join the server again and wait more before using any command.' - -# Email -email: - add_email_request: '&3Please add your email to your account with the command: /email add ' - usage_email_add: '&cUsage: /email add ' - usage_email_change: '&cUsage: /email change ' - new_email_invalid: '&cInvalid new email, try again!' - old_email_invalid: '&cInvalid old email, try again!' - invalid: '&cInvalid email address, try again!' - added: '&2Email address successfully added to your account!' - add_not_allowed: '&cAdding email was not allowed.' - request_confirmation: '&cPlease confirm your email address!' - changed: '&2Email address changed correctly!' - change_not_allowed: '&cChanging email was not allowed.' - email_show: '&2Your current email address is: &f%email' - no_email_for_account: '&2You currently don''t have email address associated with this account.' - already_used: '&4The email address is already being used' - incomplete_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.' - send_failure: 'The email could not be sent. Please contact an administrator.' - change_password_expired: 'You cannot change your password using this command anymore.' - email_cooldown_error: '&cAn email was already sent recently. You must wait %time before you can send a new one.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Forgot your password? Please use the command: /email recovery ' - command_usage: '&cUsage: /email recovery ' - email_sent: '&2Recovery email sent successfully! Please check your email inbox!' - code: - code_sent: 'A recovery code to reset your password has been sent to your email.' - incorrect: 'The recovery code is not correct! You have %count tries remaining.' - tries_exceeded: 'You have exceeded the maximum number attempts to enter the recovery code. Use "/email recovery [email]" to generate a new one.' - correct: 'Recovery code entered correctly!' - change_password: 'Please use the command /email setpassword to change your password immediately.' - -# Captcha -captcha: - usage_captcha: '&3To log in you have to solve a captcha code, please use the command: /captcha %captcha_code' - wrong_captcha: '&cWrong captcha, please type "/captcha %captcha_code" into the chat!' - valid_captcha: '&2Captcha code solved correctly!' - captcha_for_registration: 'To register you have to solve a captcha first, please use the command: /captcha %captcha_code' - register_captcha_valid: '&2Valid captcha! You may now register with /register' - -# Verification code -verification: - code_required: '&3This command is sensitive and requires an email verification! Check your inbox and follow the email''s instructions.' - command_usage: '&cUsage: /verification ' - incorrect_code: '&cIncorrect code, please type "/verification " into the chat, using the code you received by email' - success: '&2Your identity has been verified! You can now execute all commands within the current session!' - already_verified: '&2You can already execute every sensitive command within the current session!' - code_expired: '&3Your code has expired! Execute another sensitive command to get a new code!' - email_needed: '&3To verify your identity you need to link an email address with your account!!' - -# Time units -time: - second: 'second' - seconds: 'seconds' - minute: 'minute' - minutes: 'minutes' - hour: 'hour' - hours: 'hours' - day: 'day' - days: 'days' - -# Two-factor authentication -two_factor: - code_created: '&2Your secret code is %code. You can scan it from here %url' - confirmation_required: 'Please confirm your code with /2fa confirm ' - code_required: 'Please submit your two-factor authentication code with /2fa code ' - already_enabled: 'Two-factor authentication is already enabled for your account!' - enable_error_no_code: 'No 2fa key has been generated for you or it has expired. Please run /2fa add' - enable_success: 'Successfully enabled two-factor authentication for your account' - enable_error_wrong_code: 'Wrong code or code has expired. Please run /2fa add' - not_enabled_error: 'Two-factor authentication is not enabled for your account. Run /2fa add' - removed_success: 'Successfully removed two-factor auth from your account' - invalid_code: 'Invalid code!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock auto login success!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aYou are stuck in portal during login.' - fix_underground: '&aYou are stuck underground during login.' - cannot_fix_underground: '&aYou are stuck underground during login, but we cant fix it.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cYou have been disconnected due to doubled login.' diff --git a/src/main/resources/messages/messages_eo.yml b/src/main/resources/messages/messages_eo.yml deleted file mode 100644 index c8623f35..00000000 --- a/src/main/resources/messages/messages_eo.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cEn-ludo registriĝo estas malebligita!' - name_taken: '&cVi jam registris tiun uzantnomon!' - register_request: '&3Bonvolu registri al la servilo per la komando: /register ' - command_usage: '&cUzado: /register ' - reg_only: '&4Nur registritaj uzantoj povas aliĝi la servilon! Bonvolu viziti https://example.com registri vin mem!' - success: '&2Sukcese registris!' - kicked_admin_registered: 'Administranto ĵus registrita vin; bonvolu ensaluti denove' - -# Password errors on registration -password: - match_error: '&cLa pasvortoj ne kongruas, kontrolu ilin!' - name_in_password: '&cVi ne povas uzi vian nomon kiel pasvorto, bonvolu elekti alian...' - unsafe_password: '&cLa elektita pasvorto estas danĝere, bonvolu elekti alian...' - forbidden_characters: '&4Via pasvorto enhavas kontraŭleĝan karakteroj. Permesita signoj: %valid_chars' - wrong_length: '&cVia pasvorto estas tro mallonga aŭ tro longa! Bonvolu provi alian pasvorton!' - pwned_password: '&cVia elektita pasvorto ne estas sekura. Ĝi estis uzita %pwned_count fojojn jam! Bonvolu uzi fortan pasvorton...' - -# Login -login: - command_usage: '&cUzado: /login ' - wrong_password: '&cErara pasvorto!' - success: '&2Sukcesa ensaluto!' - login_request: '&cBonvolu ensaluti per la komando: /login ' - timeout_error: '&4Salutnomo tempolimo superis, vi estis piedbatita el la servilo, bonvolu provi denove!' - -# Errors -error: - denied_command: '&cPor uzi ĉi komando vi devas esti legalizita!' - denied_chat: '&cPor babili vi devas esti legalizita!' - unregistered_user: '&cTiu uzanto ne estas registrita!' - not_logged_in: '&cVi ne estas ensalutita!' - no_permission: '&4Vi ne havas la permeson por fari ĉi tiun funkcion!' - unexpected_error: '&4Neatendita eraro, bonvolu kontakti administranto!' - max_registration: 'Vi superis la maksimuman nombron de enregistroj (%reg_count/%max_acc %reg_names) pro via ligo!' - logged_in: '&cVi jam estas ensalutinta!' - kick_for_vip: '&3VIP ludanto aliĝis al la servilo kiam ĝi pleniĝis!' - kick_unresolved_hostname: '&cEraro okazis: neatingebla ludanta gastiga nomo!' - tempban_max_logins: '&cVi estis portempe malpermesita por ne ensaluti tro multajn fojojn.' - -# AntiBot -antibot: - kick_antibot: 'KontraŭRoboto protekto modon estas ŝaltita! Vi devas atendi kelkajn minutojn antaŭ kunigi al la servilo.' - auto_enabled: '&4[KontraŭRobotoServo] KontraŭRoboto ŝaltita pro la grandega nombro de konektoj!' - auto_disabled: '&2[KontraŭRobotoServo] KontraŭRoboto malebligita post %m minutoj!' - -# Unregister -unregister: - success: '&cSukcese neregistritajn!' - command_usage: '&cUzado: /unregister ' - -# Other messages -misc: - account_not_activated: '&cVia konto ne aktivigis tamen, bonvolu kontroli viajn retpoŝtojn!' - not_activated: '&cKonto ne aktivigita, bonvolu registriĝi kaj aktivigi ĝin antaŭ ol provi denove.' - password_changed: '&2Pasvorto sukcese ŝanĝita!' - logout: '&2Elsalutita sukcese!' - reload: '&2Agordo kaj datumbazo estis larditaj korekte!' - usage_change_password: '&cUzado: /changepassword ' - accounts_owned_self: 'Vi posedas %count kontoj:' - accounts_owned_other: 'La ludanto %name havas %count kontojn::' - -# Session messages -session: - valid_session: '&2Ensalutantojn pro Sesio Rekonektas.' - invalid_session: '&cVia IP estis ŝanĝita kaj via seanco datumoj finiĝis!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Ludanto kun la sama IP jam estas en ludo!' - same_nick_online: '&4La sama uzantnomo estas jam ludas sur la servilo!' - name_length: '&4Via uzantnomo estas aŭ tro mallonga aŭ tro longa!' - characters_in_name: '&4Via uzantnomo enhavas kontraŭleĝan karakteroj. Permesita signoj: %valid_chars' - kick_full_server: '&4La servilo estas plena, reprovi poste!' - country_banned: '&4Via lando estas malpermesitaj de tiu servilo!' - not_owner_error: 'Vi ne estas la posedanto de tiu konto. Bonvolu elekti alian nomon!' - invalid_name_case: 'Vi devus aliĝi uzante uzantnomon %valid, ne %invalid.' - quick_command: 'Vi uzis komandon tro rapide! Bonvolu, re-aliĝi al la servilo kaj atendi pli longe antaŭ ol uzi iun ajn komandon.' - -# Email -email: - add_email_request: '&3Bonvolu aldoni vian retpoŝtan vian konton kun la komando: /email add ' - usage_email_add: '&cUzado: /email add ' - usage_email_change: '&cUzado: /email change ' - new_email_invalid: '&cNevalida nova retpoŝta, provu denove!' - old_email_invalid: '&cNevalida malnovaj retpoŝto, provu denove!' - invalid: '&cNevalida retadreso, provu denove!' - added: '&2Retpoŝtadreso sukcese aldonitaj al via konto!' - add_not_allowed: '&cAldoni retpoŝton ne estis permesita.' - request_confirmation: '&cBonvolu konfirmi vian retadreson!' - changed: '&2Retpoŝtadreso ŝanĝis ĝuste!' - change_not_allowed: '&cŜanĝi retpoŝton ne estis permesita.' - email_show: '&2Via nuna retadreso estas: &f%email' - no_email_for_account: '&2Vi aktuale ne havas retadreson asociita kun ĉi tiu konto.' - already_used: '&4La retpoŝto jam estas uzata' - incomplete_settings: 'Eraro: ne ĉiuj postulata agordoj estas metita por sendi retpoŝtojn. Bonvolu kontakti administranto.' - send_failure: 'La retpoŝto ne estis sendita. Bonvolu kontakti administranto.' - change_password_expired: 'Vi ne povas ŝanĝi vian pasvorton per tiu ĉi komando plu.' - email_cooldown_error: '&cRetmesaĝon jam sendita lastatempe. Vi devas atendi %time antaŭ vi povas sendi novan.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Ĉu vi forgesis vian pasvorton? Bonvolu uzi la komando: /email recovery ' - command_usage: '&cUzado: /email recovery ' - email_sent: '&2Reakiro retpoŝto sendita sukcese! Bonvolu kontroli vian retpoŝton enirkesto!' - code: - code_sent: 'Rekorda kodo restarigi vian pasvorton sendis al via retpoŝto.' - incorrect: 'La reakiro kodo estas ne korekti! Vi havas %count provoj restas.' - tries_exceeded: 'Vi superis la maksimuman nombron provas eniri la reakiro kodo. Uzo "/email recovery [retpoŝto]" por generi novan.' - correct: 'Reakiro kodo eniris ĝuste!' - change_password: 'Bonvolu uzi la komando /email setpassword ŝanĝi vian pasvorton tuj.' - -# Captcha -captcha: - usage_captcha: '&3Ensaluti vi devas solvi captcha kodo, bonvolu uzi la komando: /captcha %captcha_code' - wrong_captcha: '&cMalĝusta captcha, bonvolu tajpi "/captcha %captcha_code" en la babilejo!' - valid_captcha: '&2Captcha kodo solvita ĝuste!' - captcha_for_registration: 'Por registri vi devas unue solvi kapĉon, bonvolu uzi la komandon: /captcha %captcha_code' - register_captcha_valid: '&2Valida kapĉo! Vi nun povas registri per /register' - -# Verification code -verification: - code_required: '&3Tiu ĉi komando estas sentema kaj postulas retpoŝtan kontrolon! Kontrolu vian leterkeston kaj sekvu la instrukciojn en la retpoŝto.' - command_usage: '&cUzado: /verification ' - incorrect_code: '&cMalĝusta kodo, bonvolu tajpi "/verification " en la babilejo, uzante la kodon, kiun vi ricevis per retpoŝto' - success: '&2Via identeco estis kontrolita! Vi nun povas ekzekuti ĉiujn komandojn dum la aktuala sesio!' - already_verified: '&2Vi jam povas ekzekuti ĉiujn sentemajn komandojn dum la aktuala sesio!' - code_expired: '&3Via kodo eksvalidiĝis! Ekzekutu alian senteman komandon por ricevi novan kodon!' - email_needed: '&3Por kontroli vian identecon vi devas ligi retpoŝtan adreson kun via konto!' - -# Time units -time: - second: 'sekundo' - seconds: 'sekundoj' - minute: 'minuto' - minutes: 'minutoj' - hour: 'horo' - hours: 'horoj' - day: 'tago' - days: 'tagoj' - -# Two-factor authentication -two_factor: - code_created: '&2Via sekreta kodo estas %code. Vi povas skani ĝin de tie %url' - confirmation_required: 'Bonvolu konfirmi vian kodon per /2fa confirm ' - code_required: 'Bonvolu sendi vian du-faktoran aŭtentikigan kodon per /2fa code ' - already_enabled: 'Du-faktora aŭtentikigo jam estas ebligita por via konto!' - enable_error_no_code: 'Neniu 2fa ŝlosilo estis generita por vi aŭ ĝi eksvalidiĝis. Bonvolu kuri /2fa add' - enable_success: 'Sukcese ebligis du-faktoran aŭtentikigon por via konto' - enable_error_wrong_code: 'Malĝusta kodo aŭ kodo eksvalidiĝis. Bonvolu kuri /2fa add' - not_enabled_error: 'Du-faktora aŭtentikigo ne estas ebligita por via konto. Kuru /2fa add' - removed_success: 'Sukcese forigis du-faktoran aŭtentikigon de via konto' - invalid_code: 'Nevalida kodo!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aSukcesa Bedrock-aŭtomata ensaluto!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aVi estas blokita en portalo dum ensaluto.' - fix_underground: '&aVi estas blokita subtere dum ensaluto.' - cannot_fix_underground: '&aVi estas blokita subtere dum ensaluto, sed ni ne povas ripari ĝin.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cVi estis malkonektita pro duobla ensaluto.' diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml deleted file mode 100644 index fbded288..00000000 --- a/src/main/resources/messages/messages_es.yml +++ /dev/null @@ -1,174 +0,0 @@ -# This file must be in ANSI if win, or UTF-8 if linux. -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cEl registro está desactivado' - name_taken: '&cUsuario ya registrado' - register_request: '&cPor favor, regístrate con "/register ' - command_usage: '&cUso: /register Contraseña ConfirmarContraseña' - reg_only: '&f¡Sólo para jugadores registrados! Por favor visita https://www.example.com/ para registrarte' - success: '&c¡Registrado correctamente!' - kicked_admin_registered: 'Un administrador te acaba de registrar; entra en la cuenta de nuevo' - -# Password errors on registration -password: - match_error: '&fLas contraseñas no son iguales' - name_in_password: '&cNo puedes utilizar tu nombre como contraseña. Por favor, elija otra...' - unsafe_password: '&cLa contraseña elegida no es segura, por favor elija otra...' - forbidden_characters: '&cTu contraseña tiene carácteres no admitidos, los cuales son: %valid_chars' - wrong_length: '&fTu contraseña es muy larga o muy corta' - pwned_password: '&cLa contraseña elegida no es segura. ¡Se ha usado %pwned_count veces ya! Por favor, use una contraseña fuerte...' - -# Login -login: - command_usage: '&cUso: /login contraseña' - wrong_password: '&cContraseña incorrecta' - success: '&c¡Sesión iniciada!' - login_request: '&cInicia sesión con "/login contraseña"' - timeout_error: '&fTiempo de espera para inicio de sesión excedido' - -# Errors -error: - denied_command: '&c¡Para utilizar este comando debes iniciar sesión!' - denied_chat: '&c¡Para poder hablar en el chat debes iniciar sesión!' - unregistered_user: '&cUsuario no registrado' - not_logged_in: '&c¡No has iniciado sesión!' - no_permission: '&cNo tienes permiso' - unexpected_error: '&fHa ocurrido un error. Por favor contacta al administrador.' - max_registration: '&fHas excedido la cantidad máxima de registros para tu cuenta' - logged_in: '&c¡Ya has iniciado sesión!' - kick_for_vip: '&c¡Un jugador VIP ha ingresado al servidor lleno!' - kick_unresolved_hostname: '&cSe produjo un error: nombre de host del jugador no resuelto!' - tempban_max_logins: '&cHas sido expulsado temporalmente por intentar iniciar sesión demasiadas veces.' - -# AntiBot -antibot: - kick_antibot: '¡El modo de protección AntiBot está habilitado! Tienes que esperar varios minutos antes de entrar en el servidor.' - auto_enabled: '[AuthMe] AntiBotMod activado automáticamente debido a conexiones masivas!' - auto_disabled: '[AuthMe] AntiBotMod desactivado automáticamente después de %m minutos. Esperamos que haya terminado' - -# Unregister -unregister: - success: '&c¡Cuenta eliminada del registro!' - command_usage: '&cUso: /unregister contraseña' - -# Other messages -misc: - account_not_activated: '&fTu cuenta no está activada aún, ¡revisa tu correo!' - not_activated: '&cCuenta no activada, por favor regístrese y actívela antes de intentarlo de nuevo.' - password_changed: '&c¡Contraseña cambiada!' - logout: '&cDesconectado correctamente.' - reload: '&fLa configuración y la base de datos han sido recargados' - usage_change_password: '&fUso: /changepw contraseñaActual contraseñaNueva' - accounts_owned_self: 'Eres propietario de %count cuentas:' - accounts_owned_other: 'El jugador %name tiene %count cuentas:' - -# Session messages -session: - valid_session: '&cInicio de sesión' - invalid_session: '&fLos datos de sesión no corresponden. Por favor espera a terminar la sesión.' - -# Error messages when joining -on_join_validation: - same_ip_online: '¡Un jugador con la misma IP ya está en el juego!' - same_nick_online: '&fYa hay un usuario con ese nick conectado (posible error)' - name_length: '&cTu nombre de usuario es muy largo o muy corto.' - characters_in_name: '&cTu usuario tiene carácteres no admitidos, los cuales son: %valid_chars' - kick_full_server: '&c¡El servidor está lleno, lo sentimos!' - country_banned: '¡Tu país ha sido baneado de este servidor!' - not_owner_error: 'No eres el propietario de esta cuenta. ¡Por favor, elije otro nombre!' - invalid_name_case: 'Solo puedes unirte mediante el nombre de usuario %valid, no %invalid.' - quick_command: 'Has usado el comando demasiado rápido! Porfavor, entra al servidor de nuevo y espera un poco antes de usar cualquier comando.' - -# Email -email: - add_email_request: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail' - usage_email_add: '&fUso: /email add ' - usage_email_change: '&fUso: /email change ' - new_email_invalid: '[AuthMe] Nuevo email inválido!' - old_email_invalid: '[AuthMe] Email anterior inválido!' - invalid: '[AuthMe] Email inválido' - added: '[AuthMe] Email agregado !' - add_not_allowed: '&cNo se permite añadir un Email' - request_confirmation: '[AuthMe] Confirma tu Email !' - changed: '[AuthMe] Email cambiado !' - change_not_allowed: '&cNo se permite el cambio de Email' - email_show: '&2Tu dirección de E-Mail actual es: &f%email' - no_email_for_account: '&2No tienes ningun E-Mail asociado en esta cuenta.' - already_used: '&4La dirección Email ya está siendo usada' - incomplete_settings: 'Error: no todos los ajustes necesarios se han configurado para poder enviar correos. Por favor, contacta con un administrador.' - send_failure: 'No se ha podido enviar el correo electrónico. Por favor, contacta con un administrador.' - change_password_expired: 'No puedes cambiar la contraseña utilizando este comando.' - email_cooldown_error: '&cEl correo ha sido enviado recientemente. Debes esperar %time antes de volver a enviar uno nuevo.' - -# Password recovery by email -recovery: - forgot_password_hint: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery ' - command_usage: '&fUso: /email recovery ' - email_sent: '[AuthMe] Correo de recuperación enviado !' - code: - code_sent: 'El código de recuperación para recuperar tu contraseña se ha enviado a tu correo.' - incorrect: '¡El código de recuperación no es correcto! Usa "/email recovery [email]" para generar uno nuevo' - tries_exceeded: 'Has excedido el número máximo de intentos para introducir el código de recuperación. Escribe "/email recovery [tuEmail]" para generar uno nuevo.' - correct: '¡Código de recuperación introducido correctamente!' - change_password: 'Por favor usa el comando "/email setpassword " para cambiar tu contraseña inmediatamente.' - -# Captcha -captcha: - usage_captcha: '&cUso: /captcha %captcha_code' - wrong_captcha: '&cCaptcha incorrecto, por favor usa: /captcha %captcha_code' - valid_captcha: '&c¡Captcha ingresado correctamente!' - captcha_for_registration: 'Para registrarse primero debes resolver el captcha, por favor usa el comando: /captcha %captcha_code' - register_captcha_valid: '&2¡Captcha validado! Ahora puedes registrarte usando /register' - -# Verification code -verification: - code_required: '&3¡Este comando es privado y requiere una verificación por correo electrónico! Revisa tu bandeja de entrada y sigue las instrucciones del correo electrónico.' - command_usage: '&cUso: /verification ' - incorrect_code: '&cCódigo incorrecto, por favor escribe "/verification " en el chat, utilizando el código que has recibido por correo electrónico.' - success: '&2Tu identidad ha sido verificada! Ahora puedes ejecutar todos los comandos dentro de la sesión actual.' - already_verified: '&2¡Ya puedes ejecutar todos los comandos de seguridad dentro de la sesión actual!' - code_expired: '&3Tu código ha expirado! Ejecuta otra vez el comando de seguridad para obtener un nuevo código!' - email_needed: '&3¡Para verificar tu identidad necesitas añadir tu correo electrónico a tu cuenta!' - -# Time units -time: - second: 'segundo' - seconds: 'segundos' - minute: 'minuto' - minutes: 'minutos' - hour: 'hora' - hours: 'horas' - day: 'día' - days: 'días' - -# Two-factor authentication -two_factor: - code_created: '&2Tu código secreto es %code. Lo puedes escanear desde aquí %url' - confirmation_required: 'Por favor, confirma tu código con /2fa confirm ' - code_required: 'Por favor, envía tu código de atenticación de dos factores con /2fa code ' - already_enabled: '¡La autenticación de dos factores ha sido habilitada para tu cuenta!' - enable_error_no_code: 'No se ha generado ninguna clave o código 2fa o ha expirado. Por favor usa /2fa add' - enable_success: 'Se ha habilitado correctamente la autenticación de dos factores para tu cuenta' - enable_error_wrong_code: 'El código es incorrecto o ha expirado. Por favor usa /2fa add' - not_enabled_error: 'La autenticación de dos factores no está habilitada para tu cuenta. Por favor usa /2fa add' - removed_success: 'Se ha eliminado correctamente la autenticación de dos factores de tu cuenta' - invalid_code: '¡Código incorrecto!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&a¡Inicio de sesión automático de Bedrock exitoso!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aEstás atascado en el portal durante el inicio de sesión.' - fix_underground: '&aEstás atascado bajo tierra durante el inicio de sesión.' - cannot_fix_underground: '&aEstás atascado bajo tierra durante el inicio de sesión, pero no podemos solucionarlo.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cHas sido desconectado debido a un inicio de sesión doble.' diff --git a/src/main/resources/messages/messages_et.yml b/src/main/resources/messages/messages_et.yml deleted file mode 100644 index 8f940ed5..00000000 --- a/src/main/resources/messages/messages_et.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cMängusisene registreerimine on välja lülitatud!' - name_taken: '&cSee kasutaja on juba registreeritud!' - register_request: '&3Palun registreeri käsklusega: /register ' - command_usage: '&cKasutus: /register ' - reg_only: '&4Vaid registreeritud mängijad saavad serveriga liituda! Enda kasutaja registreerimiseks külasta https://example.com!' - success: '&2Edukalt registreeritud!' - kicked_admin_registered: 'Administraator registreeris su kasutaja, palun logi uuesti sisse.' - -# Password errors on registration -password: - match_error: '&cParoolid ei kattu, palun proovi uuesti!' - name_in_password: '&cSa ei saa oma kasutajanime paroolina kasutada, palun vali mõni teine parool.' - unsafe_password: '&cSee parool ei ole turvaline, palun vali mõni teine parool.' - forbidden_characters: '&4Sinu parool sisaldab keelatud tähemärke. Lubatud tähemärgid: %valid_chars' - wrong_length: '&cSinu parool on liiga pikk või lühike, palun vali mõni teine parool.' - pwned_password: '&cTeie valitud parool ei ole turvaline. Seda on kasutatud juba %pwned_count korda! Palun kasutage tugevat parooli...' - -# Login -login: - command_usage: '&cKasutus: /login ' - wrong_password: '&cVale parool!' - success: '&2Edukalt sisselogitud!' - login_request: '&cPalun logi sisse kasutades käsklust: /login ' - timeout_error: '&4Sisselogimiseks antud aeg on läbi ning sind on serverist välja visatud, palun proovi uuesti!' - -# Errors -error: - denied_command: '&cSelle käskluse kasutamiseks pead olema sisselogitud!' - denied_chat: '&cVestlemiseks pead olema sisselogitud!' - unregistered_user: '&cSee kasutaja ei ole registreeritud!' - not_logged_in: '&cSa ei ole sisselogitud!' - no_permission: '&4Sul puudub selle käskluse kasutamiseks luba.' - unexpected_error: '&4Esines ootamatu tõrge, palun teavita administraatorit!' - max_registration: '&cSinu IP-aadressile on registreeritud liiga palju kasutajaid! (%reg_count/%max_acc %reg_names)' - logged_in: '&cSa oled juba sisselogitud!' - kick_for_vip: '&3VIP-mängija liitus serveriga ajal, mil see oli täis!' - kick_unresolved_hostname: '&cEsines tõrge: mängija hostinimi on lahendamata!' - tempban_max_logins: '&cSind on ajutiselt serverist blokeeritud, kuna sisestasid mitu korda vale parooli.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot-kaitse sisse lülitatud! Pead ootama mõne minuti enne kui serveriga liituda saad.' - auto_enabled: '&4[AntiBotTeenus] AntiBot sisselülitatud!' - auto_disabled: '&2[AntiBotTeenus] AntiBot välja lülitatud peale %m minutit!' - -# Unregister -unregister: - success: '&cKasutaja edukalt kustutatud!' - command_usage: '&cKasutus: /unregister ' - -# Other messages -misc: - account_not_activated: '&cSinu konto ei ole veel aktiveeritud, kontrolli oma meili!' - not_activated: '&cKonto ei ole aktiveeritud, palun registreerige ja aktiveerige see enne uuesti proovimist.' - password_changed: '&2Parool edukalt vahetatud!' - logout: '&2Edukalt välja logitud!' - reload: '&2Seadistused ning andmebaas on edukalt taaslaaditud!' - usage_change_password: '&cKasutus: /changepassword ' - accounts_owned_self: 'Sa omad %count kontot:' - accounts_owned_other: 'Mängijal %name on %count kontot:' - -# Session messages -session: - valid_session: '&2Sisse logitud sessiooni jätkumise tõttu.' - invalid_session: '&cSinu IP-aadress muutus, seega sinu sessioon aegus!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Sama IP-aadressiga mängija juba mängib!' - same_nick_online: '&4Sama kasutaja on juba serveriga ühendatud!' - name_length: '&4Sinu kasutajanimi on liiga pikk või liiga lühike!' - characters_in_name: '&4Sinu kasutajanimi sisaldab keelatud tähemärke. Lubatud tähemärgid: %valid_chars' - country_banned: '&4Sinu riigist ei ole võimalik sellesse serverisse ühenduda!' - not_owner_error: 'Sa ei ole selle konto omanik. Vali teine nimi!' - kick_full_server: '&4Server on täis, proovi hiljem uuesti!' - invalid_name_case: 'Sa peaksid liituma nimega %valid, mitte nimega %invalid.' - quick_command: 'Sa kasutasid käsklust liiga kiiresti! Palun liitu serveriga uuesti ning oota enne mõne käskluse kasutamist kauem.' - -# Email -email: - add_email_request: '&3Palun seo oma kasutajaga meiliaadress kasutades käsklust: /email add ' - usage_email_add: '&cKasutus: /email add ' - usage_email_change: '&cKasutus: /email change ' - new_email_invalid: '&cUus meiliaadress on sobimatu, proovi uuesti!' - old_email_invalid: '&cVana meiliaadress on sobimatu, proovi uuesti!' - invalid: '&cSobimatu meiliaadress, proovi uuesti!' - added: '&2Meiliaadress edukalt lisatud!' - add_not_allowed: '&cMeiliaadressi lisamine ei ole lubatud.' - request_confirmation: '&cPalun kinnita oma meiliaadress!' - changed: '&2Meiliaadress edukalt muudetud!' - change_not_allowed: '&cMeiliaadressi muutmine ei ole lubatud.' - email_show: '&2Sinu praegune meiliaadress on: &f%email' - no_email_for_account: '&2Selle kasutajaga ei ole seotud ühtegi meiliaadressi.' - already_used: '&4See meiliaadress on juba kasutuses!' - incomplete_settings: 'Viga: meili saatmiseks pole kõik vajalikud seaded seadistatud. Teata sellest administraatorit.' - send_failure: 'Meili ei õnnestunud saata. Teata sellest administraatorit.' - change_password_expired: 'Selle käsklusega ei saa sa enam parooli muuta.' - email_cooldown_error: '&cMeil on juba saadetud. Sa pead ootama %time enne kui saad küsida uue saatmist.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Unustasid oma parooli? Kasuta käsklust: /email recovery ' - command_usage: '&cKasutus: /email recovery ' - email_sent: '&2Konto taastamiseks vajalik meil saadetud! Vaata oma postkasti.' - code: - code_sent: 'Konto taastamise kood on saadetud!' - incorrect: 'Kood on vale! Sul on %count katset jäänud.' - tries_exceeded: 'Sul on katsed otsas. Kasuta käsklust "/email recovery [email]" uue koodi saamiseks.' - correct: 'Kood õigesti sisestatud!' - change_password: 'Palun kasuta parooli muutmiseks käsklust /email setpassword .' - -# Captcha -captcha: - usage_captcha: '&3Sisselogimiseks lahenda robotilõks käsklusega: /captcha %captcha_code' - wrong_captcha: '&cVale robotilõks, kasuta käsklust "/captcha %captcha_code"!' - valid_captcha: '&2Robotilõks lahendatud!' - captcha_for_registration: 'Registreerimiseks lahenda robotilõks kasutades käsklust: /captcha %captcha_code' - register_captcha_valid: '&2Robotilõks lahendatud! Võid nüüd registreerida kasutades käsklust /register' - -# Verification code -verification: - code_required: '&3See käsklus on ohtlik mistõttu saatsime sulle meili. Kontrolli oma meili ja järgi saadetud meili juhiseid.' - command_usage: '&cKasutus: /verification ' - incorrect_code: '&cVale kood, palun kasuta käsklust "/verification " koodiga, mille saatsime sulle meilile.' - success: '&2Sinu identiteet on kinnitatud! Sa saad nüüd praeguse sessiooni jal kasutada kõiki käsklusi.' - already_verified: '&2Sa juba saad kasutada kõiki ohtlikke käsklusi!' - code_expired: '&3Kood on aegunud! Kasuta mõnda ohtlikku käsklust, et saada uus kood!' - email_needed: '&3Konto kinnitamiseks pead siduma oma kontoga enda meiliaadressi!' - -# Time units -time: - second: 'sekund' - seconds: 'sekundit' - minute: 'minut' - minutes: 'minutit' - hour: 'tund' - hours: 'tundi' - day: 'päev' - days: 'päeva' - -# Two-factor authentication -two_factor: - code_created: '&2Sinu privaatne kood on %code. Sa saad selle skännida aadressil %url' - confirmation_required: 'Palun kinnita oma kaheastmeline autentimise kood käsklusega /2fa confirm ' - code_required: 'Palun sisesta kaheastmeline autentimise kood kasutades /2fa code ' - already_enabled: 'Kaheastmeline autentimine on juba sisselülitatud!' - enable_error_no_code: '2FA võtit ei ole genereeritud või on see aegunud. Kasuta käsklust /2fa add' - enable_success: 'Kaheastmeline autentimine edukalt sisselülitatud!' - enable_error_wrong_code: 'Vale kood või kood on aegunud. Kasuta käsklust /2fa add' - not_enabled_error: 'Kaheastmeline autentimine ei ole su kontol sisse lülitatud. Kasuta käsklust /2fa add' - removed_success: 'Sinu kontolt on edukalt eemaldatud kaheastmeline autentimine.' - invalid_code: 'Vale kood!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrocki automaatne sisselogimine õnnestus!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aOlete sisselogimise ajal portaalis kinni.' - fix_underground: '&aOlete sisselogimise ajal maa all kinni.' - cannot_fix_underground: '&aOlete sisselogimise ajal maa all kinni, kuid me ei saa seda parandada.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cTeid on ühendatud lahti kahekordse sisselogimise tõttu.' diff --git a/src/main/resources/messages/messages_eu.yml b/src/main/resources/messages/messages_eu.yml deleted file mode 100644 index 8d581be6..00000000 --- a/src/main/resources/messages/messages_eu.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cIzen ematea itxita dago!' - name_taken: '&cDagoeneko badago erabiltzaile izen hori duen norbait.' - register_request: '&cMesedez erabili "/register " izena emateko' - command_usage: '&cErabilera: /register ' - reg_only: '&fIzena eman duten jokalariak bakarrik sartu daitezke! Mesedez, eman izena https://example.com webgunean' - success: '&cEskerrik asko izena emateagatik!' - kicked_admin_registered: 'Administratzaile batek izena eman dizu, mesedez irten eta sartu zerbitzaritik.' - -# Password errors on registration -password: - match_error: '&fBi pasahitzak ez datoz bat' - name_in_password: '&cPasahitza eta erabiltzaile izena ezin dira berdinak izan. Mesedez, aukeratu beste pasahitz bat...' - unsafe_password: '&cAukeratutako pasahitza ez da segurua.Mesedez, aukeratu beste bat...' - forbidden_characters: '&4Pasahitzak ondorengo karaktereak bakarrik izan ditzake: %valid_chars' - wrong_length: '&fZure pasahitza motzegia edo luzeegia da' - pwned_password: '&cAukeratutako pasahitza ez da segurua. %pwned_count aldiz erabili da dagoeneko! Mesedez, erabili pasahitz sendo bat...' - -# Login -login: - command_usage: '&cErabilera: /login pasahitza' - wrong_password: '&cPasahitz okerra' - success: '&cSaioa hasi duzu!' - login_request: '&cMesedez erabili "/login pasahitza" saioa hasteko' - timeout_error: '&fDenbora gehiegi egon zara saioa hasi gabe.' - -# Errors -error: - denied_command: '&cHori egiteko ezinbestekoa da saioa hastea!' - denied_chat: '&cTxatean hitz egiteko ezinbestekoa da saioa hastea!' - unregistered_user: '&cErabiltzaileak ez du izena eman!' - not_logged_in: '&cEz duzu saioa hasi!' - no_permission: '&cEz daukazu baimenik' - unexpected_error: '&fUstekabeko errore bat gertatu da. Mesedez jarri harremanetan administratzaile batekin.' - max_registration: '&fKonexioko gehienezko erabiltzaile kopurua gainditu duzu (%reg_count/%max_acc %reg_names)' - logged_in: '&cDagoeneko saioa hasita duzu!' - kick_for_vip: '&cVIP erabiltzaile bati lekua egiteko kanporatua izan zara!' - kick_unresolved_hostname: '&cErrore bat geratu da: ezin izan da erabiltzailearen ostalari izena lortu!' - tempban_max_logins: '&cDenbora baterako kanporatua izan zara, pasahitza behin baino gehiagotan gaizki sartzeagatik.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot babesa aktibatuta dago! Minutu batzuk itxaron beharko dituzu berriro sartu aurretik.' - auto_enabled: '&4[AntiBotZerbitzua] AntiBot babesa aktibatu da konexio kopurua handia delako!' - auto_disabled: '&2[AntiBotZerbitzua] AntiBot babesa desaktibatu da %m minutuz martxan egon ondoren!' - -# Unregister -unregister: - success: '&cZure kontua ezabatu duzu!' - command_usage: '&cErabilera: /unregister ' - -# Other messages -misc: - account_not_activated: '&fZure kontua aktibatu gabe dago. Mesedez, berretsi zure posta elektronikoa!' - not_activated: '&cKontua ez dago aktibatuta, mesedez erregistratu eta aktibatu berriro saiatu aurretik.' - password_changed: '&cPasahitza ondo aldatu duzu!' - logout: '&cSaioa itxi duzu' - reload: '&fEzarpenak eta datu-basea berrabiarazi dira' - usage_change_password: '&fErabilera: /changepassword ' - accounts_owned_self: '%count kontu dituzu:' - accounts_owned_other: '%name erabiltzaileak %count kontu ditu:' - -# Session messages -session: - valid_session: '&cSesioa mantendu eta beraz ez daukazu saioa hasi beharrik.' - invalid_session: '&cZure IP helbidea aldatu da, eta horregatik zure sesioa iraungi da!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'IP helbide bera duen beste erabiltzaile bat dago zerbitzarian!' - same_nick_online: '&fErabiltzaile izen bera duen erabailtzaile bat dago zerbitzarian' - name_length: '&cZure erabiltzaile izena motzegia edo luzeegia da' - characters_in_name: '&cZure erabiltzaileak debekatutako karaktereak ditu. Ondorengoak bakarrik onartzen ditugu: %valid_chars' - kick_full_server: '&cZerbitzaria beteta dago. Sentitzen dugu!' - country_banned: 'Zure herrialdetik ezin zara zerbitzari honetan sartu' - not_owner_error: 'Kontu hau ez da zurea! Erabili beste bat!' - invalid_name_case: '%valid erabiltzailea erabili beharko duzu, ez %invalid.' - quick_command: 'Komandoa azkarregi exekutatu duzu! Mesdez, sartu zerbitzarian berriro eta itxaron pixka bat ezer idatzi aurretik.' - -# Email -email: - add_email_request: '&cMesedez, sartu zure posta elektroniko helbidea : /email add ' - usage_email_add: '&fErabilera: /email add ' - usage_email_change: '&fErabilera: /email change ' - new_email_invalid: 'Helbide berria okerra da!' - old_email_invalid: 'Lehengo helbidea ez dator bat!' - invalid: 'Helbide okerra' - added: 'Helbidea ondo sartu duzu' - add_not_allowed: '&cEzin duzu posta helbiderik sartu' - request_confirmation: 'Berretsi zure posta helbidea!' - changed: 'Posta helbidea ondo aldatu duzu' - change_not_allowed: '&cEzin duzu posta helbidea aldatu' - email_show: '&2Zure posta helbidea ondorengoa da: &f%email' - no_email_for_account: '&2Ez daukazu posta helbiderik kontu honetara lotuta.' - already_used: '&4Posta helbide hori dagoeneko badarabil norbaitek' - incomplete_settings: 'Errorea: posta elektronikoak bidaltzeko ezparpen guztiak ez daude konfiguratu. Mesedez, jarri harremanetan administratzaile batekin.' - send_failure: 'Ezin izan da mezua bidali. Mesedez, jarri harremanetan administratzaile batekin.' - change_password_expired: 'Pasahitza aldatzeko denbora iraungi da.' - email_cooldown_error: '&cMezu bat bidali dizugu duela denbora gutxik. %time itxaron behar duzu berriro bidaltzeko eskatu aurretik.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cPasahitza ahaztu duzu? Berreskuratzeko erabili /email recovery ' - command_usage: '&fErabili: /email recovery ' - email_sent: 'Berreskuratze mezua bidali dizugu. Mesedez begiratu sarrera ontzia!' - code: - code_sent: 'Pasahitza berreskuratzeko kode bat bidali dizugu zure posta elektronikora.' - incorrect: 'Berreskuratze kodea ez da zuzena! %count saiakera dituzu.' - tries_exceeded: 'Berreskuratze kodea sartzeko gehienezko saiakera kopurua gainditu duzu. Erabili "/email recovery [helbidea]" berri bat jasotzeko.' - correct: 'Kode zuzena!' - change_password: 'Mesedez, erabili "/email setpassword pasahitza aldatzeko.' - -# Captcha -captcha: - usage_captcha: '&3Sartzeko captcha asmatu beharko duzu. Mesedez erabaili /captcha %captcha_code' - wrong_captcha: '&cCaptacha okerra, mesedez, idatzi "/captcha %captcha_code" txatean!' - valid_captcha: '&2Captcha asmatu duzu!' - captcha_for_registration: 'Izena emateko captcha asmatu beharko duzu, mesedez erabili ondorengo komandoa: /captcha %captcha_code' - register_captcha_valid: '&2Captcha zuzena! Orain izena eman dezakezu /register erabilita' - -# Verification code -verification: - code_required: '&3Komando hori babestuta dago, eta horregatik eposta berrespena beharrazkoa da! Begiratu zure sarrera ontzia, eta jarraitu bertan adierazitako pausoak.' - command_usage: '&cErabilera: /verification ' - incorrect_code: '&cKode okerra, mesedez idatzi "/verification " txatean, postan jaso duzun kodea erabilita' - success: '&2Zure identitatea berretsi duzu! Orain komando babestuak erabiltzeko baimena daukazu sesioak irauten duen bitartean!' - already_verified: '&2Dagoeneko badaukazu komando babestuak erabiltzeko baimena sesio honek irauten duen bitartean!' - code_expired: '&3Kodea iraungi egin da! Exekutatu beste komando babestu bat kode berri bat lortzeko!' - email_needed: '&3Zure identitatea berresteko beharrezkoa da zure kontuan posta elektronikoa konfiguratuta izatea!!' - -# Time units -time: - second: 'segundu' - seconds: 'segundu' - minute: 'minutu' - minutes: 'minutu' - hour: 'ordu' - hours: 'ordu' - day: 'egun' - days: 'egun' - -# Two-factor authentication -two_factor: - code_created: '&2Zure kode sekretua %code da. Hemen eskaneatu dezakezu: %url' - confirmation_required: 'Mesedez, berretsi kodea ondorengoa erabilita: /2fa confirm ' - code_required: 'Mesedez, bidali zure bi faktoreko autentikazio kodea ondorengoa erabilita: /2fa code ' - already_enabled: 'Dagoeneko badaukazu bi faktoreko autentikazioa aktibatuta!' - enable_error_no_code: 'Ez duzu 2fa koderik sortu, edo iraungita dago. Mesedez, erabili /2fa add' - enable_success: '2 faktoreko autentikazioa aktibatu duzu' - enable_error_wrong_code: 'Kode okerra, edo iraungita dago. Mesedez erabili /2fa add' - not_enabled_error: 'Ez duzu 2 faktore autentikazioa konfiguratu. Erabaili /2fa add' - removed_success: '2 faktoreko autentikazioa desaktibatu duzu' - invalid_code: 'Kode okerra!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock automatikoki saioa hasi da!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aPortal batean trabatuta zaude saioa hasten ari zarela.' - fix_underground: '&aLur azpian trabatuta zaude saioa hasten ari zarela.' - cannot_fix_underground: '&aLur azpian trabatuta zaude saioa hasten ari zarela, baina ezin dugu konpondu.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cSistematik kanporatu zaitugu saio bikoitza egiteagatik.' diff --git a/src/main/resources/messages/messages_fi.yml b/src/main/resources/messages/messages_fi.yml deleted file mode 100644 index 8d349f77..00000000 --- a/src/main/resources/messages/messages_fi.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRekisteröinti on suljettu!' - name_taken: '&cPelaaja on jo rekisteröity' - register_request: '&cRekisteröidy palvelimellemme komennolla "/register "' - command_usage: '&cKäyttötapa: /register ' - reg_only: '&fMene sivustolle: https://example.com rekisteröityäksesi!' - success: '&cRekisteröidyit onnistuneesti!' - kicked_admin_registered: 'Ylläpitäjä rekisteröi sinut juuri; kirjaudu sisään uudelleen.' - -# Password errors on registration -password: - match_error: '&fSalasanat ei täsmää' - name_in_password: '&cEt voi käyttää nimeäsi salasanana, valitse toinen...' - unsafe_password: '&cValitsemasi salasana ei ole turvallinen, valitse toinen...' - forbidden_characters: '&4Salasanassasi on kiellettyjä merkkejä. Sallitut merkit: %valid_chars' - wrong_length: '&fSalasanasi on liian pitkä tai lyhyt.' - pwned_password: '&cValitsemasi salasana ei ole turvallinen. Sitä on käytetty %pwned_count kertaa jo! Käytä vahvaa salasanaa...' - -# Login -login: - command_usage: '&cKäyttötapa: /login salasana' - wrong_password: '&cVäärä salasana' - success: '&cKirjauduit onnistuneesti' - login_request: '&cKirjaudu palvelimmelle komennolla "/login salasana"' - timeout_error: '&fKirjautumisaika meni umpeen.' - -# Errors -error: - denied_command: '&cSinun on oltava todennettu käyttääksesi tätä komentoa!' - denied_chat: '&cSinun on oltava todennettu voidaksesi chattailla!' - unregistered_user: '&cSalasanat eivät täsmää' - not_logged_in: '&cEt ole kirjautunut sisään!' - no_permission: '&cEi oikeuksia' - unexpected_error: '&fVirhe: Ota yhteys palveluntarjoojaan!' - max_registration: '&fSinulla ei ole oikeuksia tehdä enempää pelaajatilejä!' - logged_in: '&cOlet jo kirjautunut!' - kick_for_vip: '&cVIP pelaaja liittyi täyteen palvelimeen!' - kick_unresolved_hostname: '&cTapahtui virhe: pelaajan verkkonimiä ei voitu ratkaista!' - tempban_max_logins: '&cSinut on tilapäisesti kielletty liian monen kirjautumisen epäonnistumisen vuoksi.' - -# AntiBot -antibot: - kick_antibot: 'Antibot-suojatila on käytössä! Sinun on odotettava muutama minuutti ennen kuin voit liittyä palvelimelle.' - auto_enabled: '&4[AntiBotService] Antibot otettu käyttöön suuren yhteyksien määrän vuoksi!' - auto_disabled: '&2[AntiBotService] Antibot poistettu käytöstä %m minuutin kuluttua!' - -# Unregister -unregister: - success: '&cPelaajatili poistettu onnistuneesti!' - command_usage: '&cKäyttötapa: /unregister password' - -# Other messages -misc: - account_not_activated: '&fKäyttäjäsi ei ole vahvistettu!' - not_activated: '&cTiliä ei ole aktivoitu, rekisteröidy ja aktivoi se ennen kuin yrität uudelleen.' - password_changed: '&cSalasana vaihdettu!!' - logout: '&cKirjauduit ulos palvelimelta.' - reload: '&fAsetukset uudelleenladattu' - usage_change_password: '&fKäyttötapa: /changepassword vanhaSalasana uusiSalasana' - accounts_owned_self: 'Omistat %count tiliä:' - accounts_owned_other: 'Pelaajalla %name on %count tiliä:' - -# Session messages -session: - valid_session: '&cIstunto jatkettu!' - invalid_session: '&fIstunto ei täsmää! Ole hyvä ja odota istunnon loppuun' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Sama IP-osoitteella oleva pelaaja on jo pelissä!' - same_nick_online: '&COlet jo palvelimella! &COdota käyttäjän aikakatkaisua tai ota yhteyttä palveluntarjoojaan.' - name_length: '&cPelaajanimesi on liian lyhyt tai pitkä' - characters_in_name: '&cPelaajanimesi sisältää luvattomia merkkejä. Hyväksytyt merkit: %valid_chars' - kick_full_server: '&cPalvelin on täynnä, Yritä pian uudelleen!' - country_banned: '&4Maasi on estetty tästä palvelimesta!' - not_owner_error: 'Et ole tämän tilin omistaja. Valitse toinen nimi!' - invalid_name_case: 'Sinun pitäisi liittyä käyttäen käyttäjänimeä %valid, ei %invalid.' - quick_command: 'Käytit komentoa liian nopeasti! Kirjaudu sisään uudelleen ja odota enemmän ennen minkään komennon käyttöä.' - -# Email -email: - add_email_request: '&cLisää sähköpostisi: /email add sähköpostisi sähköpostisiUudelleen' - usage_email_add: '&fKäyttötapa: /email add ' - usage_email_change: '&fKäyttötapa: /email change ' - new_email_invalid: '[AuthMe] Uusi sähköposti on väärä!' - old_email_invalid: '[AuthMe] Vanha sähköposti on väärä!' - invalid: '[AuthMe] Väärä sähköposti' - added: '[AuthMe] Sähköposti lisätty!' - add_not_allowed: '&cSähköpostin lisääminen ei ollut sallittua.' - request_confirmation: '[AuthMe] Vahvistuta sähköposti!' - changed: '[AuthMe] Sähköposti vaihdettu!' - change_not_allowed: '&cSähköpostin muuttaminen ei ollut sallittua.' - email_show: '&2Nykyinen sähköpostiosoitteesi on: &f%email' - no_email_for_account: '&2Sinulla ei tällä hetkellä ole liitettyä sähköpostiosoitetta tähän tiliin.' - already_used: '&4Sähköpostiosoite on jo käytössä' - incomplete_settings: 'Virhe: kaikki tarvittavat asetukset eivät ole asetettu sähköpostien lähettämistä varten. Ota yhteyttä ylläpitäjään.' - send_failure: 'Sähköpostia ei voitu lähettää. Ota yhteyttä järjestelmänvalvojaan.' - change_password_expired: 'Et voi enää vaihtaa salasanaa tällä komennolla.' - email_cooldown_error: '&cSähköpostia on jo lähetetty äskettäin. Sinun on odotettava %time ennen kuin voit lähettää uuden.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cUnohtuiko salasana? Käytä komentoa: /email recovery ' - command_usage: '&fKäyttötapa: /email recovery ' - email_sent: '[AuthMe] Palautus sähköposti lähetetty!' - code: - code_sent: 'Salasanasi palauttamiseksi lähetetty palautuskoodi on lähetetty sähköpostiisi.' - incorrect: 'Palautuskoodi ei ole oikea! Sinulla on %count yritystä jäljellä.' - tries_exceeded: 'Olet ylittänyt enimmäisyritysten määrän palautuskoodin syöttämisessä. Käytä "/email recovery [email]" luodaksesi uuden.' - correct: 'Palautuskoodi syötetty oikein!' - change_password: 'Käytä komentoa /email setpassword vaihtaaksesi salasanasi välittömästi.' - -# Captcha -captcha: - usage_captcha: '&cKäyttötapa: /captcha %captcha_code' - wrong_captcha: '&cVäärä varmistus, käytä : /captcha %captcha_code' - valid_captcha: '&cSinun varmistus onnistui.!' - captcha_for_registration: 'Rekisteröityäksesi sinun on ensin ratkaistava captcha, käytä komentoa: /captcha %captcha_code' - register_captcha_valid: '&2Validi captcha! Voit nyt rekisteröityä käyttäen komentoa /register' - -# Verification code -verification: - code_required: '&3Tämä komento on herkkä ja vaatii sähköpostivahvistuksen! Tarkista sähköpostisi ja seuraa sähköpostin ohjeita.' - command_usage: '&cKäyttö: /verification ' - incorrect_code: '&cVirheellinen koodi, kirjoita "/verification " chatiin, käyttäen koodia, jonka sait sähköpostitse' - success: '&2Henkilöllisyytesi on varmennettu! Voit nyt suorittaa kaikki komennot tämän istunnon aikana!' - already_verified: '&2Voit jo suorittaa jokaisen herkän komennon tämän istunnon aikana!' - code_expired: '&3Koodisi on vanhentunut! Suorita toinen herkkä komento saadaksesi uuden koodin!' - email_needed: '&3Vahvistaaksesi henkilöllisyytesi sinun on liitettävä sähköpostiosoite tilillesi!!' - -# Time units -time: - second: 'sekunti' - seconds: 'sekuntia' - minute: 'minuutti' - minutes: 'minuuttia' - hour: 'tunti' - hours: 'tuntia' - day: 'päivä' - days: 'päivää' - -# Two-factor authentication -two_factor: - code_created: '&2Salainen koodisi on %code. Voit skannata sen täältä %url' - confirmation_required: 'Vahvista koodisi komennolla /2fa confirm ' - code_required: 'Lähetä kaksivaiheisen todennuksen koodisi komennolla /2fa code ' - already_enabled: 'Kaksivaiheinen todennus on jo käytössä tililläsi!' - enable_error_no_code: 'Sinulle ei ole luotu kaksivaiheisen todennuksen avainta tai se on vanhentunut. Suorita komento /2fa add' - enable_success: 'Kaksivaiheinen todennus onnistuneesti käytössä tililläsi' - enable_error_wrong_code: 'Väärä koodi tai koodi on vanhentunut. Suorita komento /2fa add' - not_enabled_error: 'Kaksivaiheista todennusta ei ole käytössä tililläsi. Suorita komento /2fa add' - removed_success: 'Kaksivaiheinen todennus poistettu tililtäsi onnistuneesti' - invalid_code: 'Virheellinen koodi!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock-automaattinen sisäänkirjautuminen onnistui!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aOlet jumissa portaalissa sisäänkirjautumisen aikana.' - fix_underground: '&aOlet jumissa maan alla sisäänkirjautumisen aikana.' - cannot_fix_underground: '&aOlet jumissa maan alla sisäänkirjautumisen aikana, mutta emme voi korjata sitä.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cSinut on katkaistu kaksoiskirjautumisen vuoksi.' diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml deleted file mode 100644 index 7fbf2e0a..00000000 --- a/src/main/resources/messages/messages_fr.yml +++ /dev/null @@ -1,176 +0,0 @@ -# Traduction par: André & Twonox - -# Pour afficher une apostrophe, vous devez en mettre deux consécutivement (ex: «J''ai» au lieu de «J'ai») -# Liste des tags globaux: -# %nl% - Permet de passer à la ligne. -# %username% - Affiche le pseudo du joueur recevant le message. -# %displayname% - Affiche le pseudo, avec couleurs, du joueur recevant le message. - -# Enregistrement -registration: - disabled: '&cL''inscription est désactivée.' - name_taken: '&cUtilisateur déjà inscrit.' - register_request: '&cPour vous inscrire, utilisez "/register "' - command_usage: '&cUsage: /register ' - reg_only: 'Seul les joueurs enregistrés sont admis!%nl%Veuillez vous rendre sur https://www.example.com pour plus d''infos.' - success: '&aInscription effectuée !' - kicked_admin_registered: 'Un admin vient de vous inscrire, veuillez vous reconnecter.' - -# Erreur de mot de passe lors de l'enregistrement -password: - match_error: '&cLe mot de passe de confirmation ne correspond pas.' - name_in_password: '&cVous ne pouvez pas utiliser votre pseudo comme mot de passe.' - unsafe_password: '&cCe mot de passe n''est pas accepté, choisissez-en un autre.' - forbidden_characters: '&cVotre mot de passe contient des caractères non autorisés. Caractères permis : %valid_chars' - wrong_length: '&cVotre mot de passe est trop court ou trop long !' - pwned_password: '&cLe mot de passe choisi n''est pas sécurisé. Il a déjà été utilisé %pwned_count fois ! Veuillez utiliser un mot de passe fort...' - -# Identification -login: - command_usage: '&cUsage: /login ' - wrong_password: '&cMauvais mot de passe !' - success: '&aIdentification effectuée !' - login_request: '&cPour vous identifier, utilisez "/login "' - timeout_error: 'Vous avez été expulsé car vous êtes trop lent pour vous enregistrer/identifier !' - -# Erreurs -error: - denied_command: '&cVous devez être connecté pour pouvoir utiliser cette commande.' - denied_chat: '&cVous devez être connecté pour pouvoir écrire dans le chat.' - unregistered_user: '&cUtilisateur non-inscrit.' - not_logged_in: '&cUtilisateur non connecté !' - no_permission: '&cVous n''êtes pas autorisé à utiliser cette commande.' - unexpected_error: '&cUne erreur est apparue, veuillez contacter un administrateur.' - max_registration: 'Vous avez atteint la limite d''inscription !%nl%&cVous avez %reg_count sur %max_acc : %reg_names' - logged_in: '&aVous êtes déjà connecté.' - kick_for_vip: 'Un joueur VIP a rejoint le serveur à votre place (serveur plein).' - kick_unresolved_hostname: '&cUne erreur est apparue : nom d''hôte non identifié !' - tempban_max_logins: '&cVous êtes temporairement banni suite à plusieurs échecs de connexions !' - -# AntiBot -antibot: - kick_antibot: 'L''AntiBot est activé, veuillez attendre %m minutes avant de joindre le serveur.' - auto_enabled: 'L''AntiBot a été activé automatiquement à cause de nombreuses connexions !' - auto_disabled: 'L''AntiBot a été désactivé automatiquement après %m minutes, espérons que l''invasion se soit arrêtée !' - -# Dé-enregistrement -unregister: - success: '&aCompte supprimé !' - command_usage: '&cPour supprimer votre compte, utilisez "/unregister "' - -# Autres messages -misc: - account_not_activated: '&fCe compte n''est pas actif, consultez vos mails !' - not_activated: '&cCompte non activé, veuillez vous inscrire et l''activer avant de réessayer.' - password_changed: '&aMot de passe changé avec succès !' - logout: '&cVous avez été déconnecté !' - reload: '&aAuthMe a été relancé avec succès.' - usage_change_password: '&cPour changer de mot de passe, utilisez "/changepassword "' - accounts_owned_self: 'Vous avez %count comptes:' - accounts_owned_other: 'Le joueur %name a %count comptes:' - -# Session -session: - valid_session: '&aVous avez été automatiquement connecté !' - invalid_session: 'Session expirée suite à un changement d''IP.' - -# Erreurs lors d'une tentative connexion -on_join_validation: - same_ip_online: 'Un joueur avec la même adresse IP joue déjà !' - same_nick_online: 'Un joueur ayant le même pseudo est déjà connecté.' - name_length: 'Votre pseudo est trop long ou trop court.' - characters_in_name: 'Caractères de pseudo autorisés: %valid_chars' - kick_full_server: '&cLe serveur est actuellement plein, désolé !' - country_banned: 'Votre pays est banni de ce serveur.' - not_owner_error: 'Vous n''êtes pas le propriétaire de ce compte. Veuillez utiliser un autre pseudo !' - invalid_name_case: 'Veuillez vous connecter avec "%valid" et non pas avec "%invalid".' - quick_command: '&cUtilisation trop rapide de commande! Veuillez vous reconnecter et attendre un peu avant d''exécuter une commande.' - -# Email -email: - add_email_request: '&cLiez votre email à votre compte en faisant "/email add "' - usage_email_add: '&fUsage: /email add ' - usage_email_change: '&fUsage: /email change ' - new_email_invalid: '&cNouvel email invalide !' - old_email_invalid: '&cAncien email invalide !' - invalid: '&cL''email inscrit est invalide !' - added: '&aEmail enregistré. En cas de perte de MDP, faites "/email recover "' - add_not_allowed: '&cVous n''êtes pas autorisé à ajouter une adresse mail.' - request_confirmation: '&cLa confirmation de l''email est manquante ou éronnée.' - changed: '&aVotre email a été mis à jour.' - change_not_allowed: '&cVous n''êtes pas autorisé à modifier l''adresse mail.' - email_show: '&fL''email enregistré pour votre compte est: %email' - no_email_for_account: '&c&oVous n''avez aucun email enregistré sur votre compte.' - already_used: '&cCet email est déjà utilisé !' - incomplete_settings: '&cErreur : Tous les paramètres requis ne sont pas présent pour l''envoi de mail, veuillez contacter un admin.' - send_failure: '&cLe mail n''a pas pu être envoyé. Veuillez contacter un admin.' - change_password_expired: 'Vous ne pouvez pas changer votre mot de passe avec cette commande.' - email_cooldown_error: '&cUn mail de récupération a déjà été envoyé récemment. Veuillez attendre %time pour le demander de nouveau.' - -# Récupération de mot de passe par mail -recovery: - forgot_password_hint: '&cVous avez oublié votre Mot de Passe? Utilisez "/email recovery "' - command_usage: '&fUsage: /email recovery ' - email_sent: '&aMail de récupération envoyé !' - code: - code_sent: 'Un code de récupération a été envoyé à votre email afin de réinitialiser votre mot de passe.' - incorrect: '&cLe code de réinitialisation est incorrect! Il vous reste %count% essai(s).' - tries_exceeded: 'Vous avez atteint le nombre maximum d''essais pour rentrer le code.%nl%Refaites "/email recovery " pour en régénérer à nouveau.' - correct: '&aCode de réinitialisation correct !' - change_password: 'Veuillez faire "/email setpassword " pour changer votre mot de passe directement.' - -# Captcha -captcha: - usage_captcha: '&cTrop de tentatives de connexion ont échoué, faites: /captcha %captcha_code' - wrong_captcha: '&cCaptcha incorrect, écrivez de nouveau: /captcha %captcha_code' - valid_captcha: '&aCaptcha validé! Vous pouvez maintenant réessayer de vous connecter.' - captcha_for_registration: 'Avant de vous inscrire, veuillez rentrer un captcha en faisant "/captcha %captcha_code"' - register_captcha_valid: '&aCaptcha validé! Vous pouvez maintenant vous inscrire.' - -# Code de vérification -verification: - code_required: '&cCette commande est sensible, elle nécessite donc une confirmation par email.%nl%&cVeuillez suivre les instructions qui viennent de vous être envoyées par email.' - command_usage: '&cUsage: /verification ' - incorrect_code: '&cCode incorrect !%nl%&cVeuillez taper "/verification " dans le chat en utilisant le code reçu par mail.' - success: '&aVotre identité a bien été vérifiée !%nl%&aVous pouvez désormais utiliser la commande souhaitée durant toute la session.' - already_verified: '&aVous êtes déjà autorisé à utiliser les commandes sensibles durant votre session actuelle.' - code_expired: '&cVotre code d''identification a expiré !%nl%&cVeuillez re-exécuter une commande sensible pour recevoir un nouveau code.' - email_needed: '&cAfin de vérifier votre identité, vous devez avoir un email lié à votre compte.%nl%&cPour cela, faites "/email add "' - -# Unités de temps -time: - second: 'seconde' - seconds: 'secondes' - minute: 'minute' - minutes: 'minutes' - hour: 'heure' - hours: 'heures' - day: 'jour' - days: 'jours' - -# Identification à deux facteurs -two_factor: - code_created: '&aVotre code secret est &2%code&a. Vous pouvez le scanner depuis &2%url' - confirmation_required: 'Veuillez confirmer votre code secret en écrivant "/2fa confirm "' - code_required: 'Veuillez indiquer votre code secret en écrivant "/2fa code "' - already_enabled: '&aL''authentification à double facteur est déjà active !' - enable_error_no_code: '&cAucun code secret n''a été généré ou bien celui-ci a expiré. Veuillez écrire "/2fa add"' - enable_success: '&aL''authentification à double facteur a été activé pour votre compte !' - enable_error_wrong_code: '&cLe code secret est faux ou bien celui-ci a expiré. Veuillez écrire "/2fa add"' - not_enabled_error: '&cL''authentification à double facteur n''est pas active sur votre compte. Faites "/2fa add" pour l''activer.' - removed_success: '&cL''authentification à double facteur a été désactivé pour votre compte !' - invalid_code: '&cCode secret invalide !' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aConnexion automatique Bedrock réussie !' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aVous êtes bloqué dans un portail lors de la connexion.' - fix_underground: '&aVous êtes bloqué sous terre lors de la connexion.' - cannot_fix_underground: '&aVous êtes bloqué sous terre lors de la connexion, mais nous ne pouvons pas le corriger.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cVous avez été déconnecté en raison d''une double connexion.' diff --git a/src/main/resources/messages/messages_gl.yml b/src/main/resources/messages/messages_gl.yml deleted file mode 100644 index 8a7a7f30..00000000 --- a/src/main/resources/messages/messages_gl.yml +++ /dev/null @@ -1,172 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cO rexistro está deshabilitado' - name_taken: '&cEse nome de usuario xa está rexistrado' - register_request: '&cPor favor, rexístrate con "/register "' - command_usage: '&cUso: /register contrasinal confirmarContrasinal' - reg_only: '&fSó xogadores rexistrados! Por favor, visita https://example.com para rexistrarte' - success: '&cRexistrado con éxito!' - kicked_admin_registered: 'Un administrador acaba de rexistrarte; por favor, volve a iniciar sesión.' - -# Password errors on registration -password: - match_error: '&fO contrasinal non coincide' - name_in_password: '&cNon podes usar o teu nome como contrasinal, por favor, escolle outro...' - unsafe_password: '&cO contrasinal escollido non é seguro, por favor, escolle outro...' - forbidden_characters: '&4O teu contrasinal contén caracteres non permitidos. Caracteres permitidos: %valid_chars' - wrong_length: '&fO teu contrasinal non alcanza a lonxitude mínima ou excede a lonxitude máxima' - pwned_password: '&cO contrasinal elixido non é seguro. Foi usado %pwned_count veces xa! Por favor, use un contrasinal forte...' - -# Login -login: - command_usage: '&cUso: /login ' - wrong_password: '&cContrasinal equivocado' - success: '&cIdentificación con éxito!' - login_request: '&cPor favor, identifícate con "/login "' - timeout_error: '&fRematou o tempo da autentificación' - -# Errors -error: - denied_command: '&cPara usar este comando debes estar autenticado!' - denied_chat: '&cPara chatear debes estar autenticado!' - unregistered_user: '&cEse nome de usuario non está rexistrado' - not_logged_in: '&cNon te identificaches!' - no_permission: '&cNon tes o permiso' - unexpected_error: '&fOcurriu un erro; contacta cun administrador' - max_registration: '&fExcediches o máximo de rexistros para a túa Conta' - logged_in: '&cXa estás identificado!' - kick_for_vip: '&cUn xogador VIP uniuse ao servidor cheo!' - kick_unresolved_hostname: '&cProduciuse un erro: nome do xogador non resolto!' - tempban_max_logins: '&cEstás temporalmente expulsado por fallar ao acceder en demasiadas ocasións.' - -# AntiBot -antibot: - kick_antibot: 'O modo de protección AntiBot está activado! Tes que agardar uns minutos antes de unirte ao servidor.' - auto_enabled: '[AuthMe] AntiBotMod conectouse automáticamente debido a conexións masivas!' - auto_disabled: '[AuthMe] AntiBotMod desactivouse automáticamente despois de %m minutos, esperemos que a invasión se detivera' - -# Unregister -unregister: - success: '&cFeito! Xa non estás rexistrado!' - command_usage: '&cUso: /unregister ' - -# Other messages -misc: - account_not_activated: '&fA túa conta aínda non está activada, comproba a túa bandexa de correo!!' - not_activated: '&cConta non activada, por favor rexístrese e actívea antes de tentalo de novo.' - password_changed: '&cCambiouse o contrasinal!' - logout: '&cSesión pechada con éxito' - reload: '&fRecargáronse a configuración e a base de datos' - usage_change_password: '&fUso: /changepassword ' - accounts_owned_self: 'Tes %count contas:' - accounts_owned_other: 'O xogador %name ten %count contas:' - -# Session messages -session: - valid_session: '&cIdentificado mediante a sesión' - invalid_session: '&fOs datos de sesión non corresponden, por favor, espere a que remate a sesión' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Un xogador coa mesma IP xa está en xogo!' - same_nick_online: '&fXa está xogando alguén co mesmo nome' - name_length: '&cO teu nome é demasiado curto ou demasiado longo' - characters_in_name: '&cO teu nome contén caracteres ilegais. Caracteres permitidos: %valid_chars' - kick_full_server: '&cO servidor está actualmente cheo, sentímolo!' - country_banned: '&4O teu país está prohibido neste servidor!' - not_owner_error: 'Non es o dono desta conta. Por favor, escolle outro nome!' - invalid_name_case: 'Deberías unirte usando o nome de usuario %valid, non %invalid.' - quick_command: 'Usaches un comando moi rápido! Por favor, úneste ao servidor de novo e agarda máis antes de usar calquera comando.' - -# Email -email: - add_email_request: '&cPor favor, engade o teu correo electrónico con: /email add ' - usage_email_add: '&fUso: /email add ' - usage_email_change: '&fUso: /email change ' - new_email_invalid: '[AuthMe] O novo correo non é válido!' - old_email_invalid: '[AuthMe] O correo vello non é válido!' - invalid: '[AuthMe] Correo non válido' - added: '[AuthMe] Correo engadido!' - add_not_allowed: '&cEngadir o correo electrónico non estaba permitido.' - request_confirmation: '[AuthMe] Confirma o teu correo!' - changed: '[AuthMe] Cambiouse o correo!' - email_show: '&2O teu enderezo de correo electrónico actual é: &f%email' - no_email_for_account: '&2Actualmente non tes ningún enderezo de correo electrónico asociado con esta conta.' - already_used: '&4O enderezo de correo electrónico xa está a ser usado' - incomplete_settings: 'Erro: non todos os axustes necesarios están configurados para enviar correos electrónicos. Por favor, contacta cun administrador.' - send_failure: 'O correo electrónico non puido ser enviado. Por favor, contacta cun administrador.' - change_password_expired: 'Non podes cambiar o teu contrasinal usando este comando máis.' - email_cooldown_error: '&cUn correo electrónico xa foi enviado recentemente. Debes agardar %time antes de poder enviar un novo.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cOlvidaches o contrasinal? Por favor, usa /email recovery ' - command_usage: '&fUso: /email recovery ' - email_sent: '[AuthMe] Enviouse o correo de confirmación!' - code: - code_sent: 'Enviouse un código de recuperación para restablecer o teu contrasinal ao teu correo electrónico.' - incorrect: 'O código de recuperación non é correcto! Tes %count intentos restantes.' - tries_exceeded: 'Excedeches o número máximo de intentos para ingresar o código de recuperación. Usa "/email recovery [email]" para xerar un novo.' - correct: 'O código de recuperación foi ingresado correctamente!' - change_password: 'Usa o comando /email setpassword para cambiar o teu contrasinal inmediatamente.' - -# Captcha -captcha: - usage_captcha: '&cNecesitas escribir un captcha, por favor escribe: /captcha %captcha_code' - wrong_captcha: '&cCaptcha equivocado, por favor usa: /captcha %captcha_code' - valid_captcha: '&cO teu captcha é válido !' - captcha_for_registration: 'Para rexistrarte debes resolver un captcha primeiro, por favor, usa o comando: /captcha %captcha_code' - register_captcha_valid: '&2Captcha válido! Agora podes rexistrarte con /register' - -# Verification code -verification: - code_required: '&3Este comando é sensible e require unha verificación por correo electrónico! Comproba a túa bandeixa de entrada e segue as instrucións do correo electrónico.' - command_usage: '&cUso: /verification ' - incorrect_code: '&cCódigo incorrecto, por favor, escribe "/verification " no chat, usando o código que recibiches por correo electrónico' - success: '&2A túa identidade foi verificada! Agora podes executar todos os comandos dentro da sesión actual!' - already_verified: '&2Xa podes executar todos os comandos sensibles dentro da sesión actual!' - code_expired: '&3O teu código caducou! Executa outro comando sensible para obter un novo código!' - email_needed: '&3Para verificar a túa identidade debes vincular un enderezo de correo electrónico á túa conta!!' - -# Time units -time: - second: 'segundo' - seconds: 'segundos' - minute: 'minuto' - minutes: 'minutos' - hour: 'hora' - hours: 'horas' - day: 'día' - days: 'días' - -# Two-factor authentication -two_factor: - code_created: '&2O teu código secreto é %code. Podes escanealo desde aquí %url' - confirmation_required: 'Por favor, confirma o teu código con /2fa confirm ' - code_required: 'Por favor, envía o teu código de autenticación en dous pasos con /2fa code ' - already_enabled: 'A autenticación en dous pasos xa está activada para a túa conta!' - enable_error_no_code: 'Non se xerou ningún clave 2fa para ti ou caducou. Por favor, executa /2fa add' - enable_success: 'Autenticación en dous pasos activada con éxito para a túa conta' - enable_error_wrong_code: 'Código incorrecto ou caducado. Por favor, executa /2fa add' - not_enabled_error: 'A autenticación en dous pasos non está activada para a túa conta. Executa /2fa add' - removed_success: 'Autenticación en dous pasos eliminada con éxito da túa conta' - invalid_code: 'Código incorrecto!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aInicio de sesión automático de Bedrock exitoso!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aEstá atrapado no portal durante o inicio de sesión.' - fix_underground: '&aEstá atrapado baixo terra durante o inicio de sesión.' - cannot_fix_underground: '&aEstá atrapado baixo terra durante o inicio de sesión, pero non podemos arranxalo.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cFoi desconectado debido a un inicio de sesión dobre.' diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml deleted file mode 100644 index 215a0660..00000000 --- a/src/main/resources/messages/messages_hu.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cA regisztráció letiltva!' - name_taken: '&cEz a játékosnév már regisztrálva van!' - register_request: '&cKérlek, regisztrálj be a következő paranccsal: "&7/register &c".' - command_usage: '&cHasználat: "&7/register &c".' - reg_only: '&4Csak a regisztrált játékosok tudnak csatlakozni a szerverhez!' - success: '&aA regisztráció sikeres!' - kicked_admin_registered: 'Adminisztrátor által regisztrálva lettél. Kérlek, lépj be újra a szerverbe!' - -# Password errors on registration -password: - match_error: '&cA két jelszó nem egyezik!' - name_in_password: '&cNem használhatod a felhasználóneved jelszónak, kérlek, válassz másikat...' - unsafe_password: '&cA választott jelszó nem biztonságos, kérlek, válassz másikat...' - forbidden_characters: '&4A választott jelszó nem engedélyezett karaktereket tartalmaz. Engedélyezett karakterek: %valid_chars' - wrong_length: 'A jelszavad nem éri el a minimális hosszúságot!' - pwned_password: '&cA választott jelszavad nem biztonságos. Már %pwned_count alkalommal használták! Kérlek használj erős jelszót...' - -# Login -login: - command_usage: '&cBejelentkezés: "&7/login &c".' - wrong_password: '&4A jelszó helytelen!' - success: '&aSikeresen beléptél!' - login_request: '&cKérlek, jelentkezz be: "&7/login &c"!' - timeout_error: 'Bejelentkezési időtúllépés!' - -# Errors -error: - denied_command: '&cAmíg nem vagy bejelentkezve, nem használhatod ezt a parancsot!' - denied_chat: '&cAmíg nem vagy bejelentkezve, nem használhatod a csevegőt!' - unregistered_user: '&cEz a felhasználó nincs regisztrálva!' - not_logged_in: '&cNem vagy bejelentkezve!' - no_permission: '&cNincs jogosultságod a használatára!' - unexpected_error: '&cHiba lépett fel! Lépj kapcsolatba a szerver tulajával!' - max_registration: '&cElérted a maximálisan beregisztrálható karakterek számát. (%reg_count/%max_acc %reg_names)' - logged_in: '&cMár be vagy jelentkezve!' - kick_for_vip: '&3VIP játékos csatlakozott a szerverhez!' - kick_unresolved_hostname: '&cHiba történt: feloldatlan játékos hosztnév!' - tempban_max_logins: '&cIdeiglenesen ki lettél tiltva, mert túl sok alkalommal rontottad el a jelszavad!' - -# AntiBot -antibot: - kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérlek, várj pár percet mielőtt csatlakozol.' - auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt, mert a megszabott időn belül több felhasználó csatlakozott!' - auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m perc múlva!' - -# Unregister -unregister: - success: '&cA regisztráció sikeresen törölve!' - command_usage: '&cHasználat: "&7/unregister &c"' - -# Other messages -misc: - account_not_activated: '&cA felhasználód aktiválása még nem történt meg, ellenőrizd a megadott emailed!' - not_activated: '&cA fiók nincs aktiválva, kérlek regisztrálj és aktiváld azt mielőtt újra megpróbálkoznál.' - password_changed: '&cA jelszó sikeresen megváltoztatva!' - logout: '&cSikeresen kijelentkeztél!' - reload: 'Beállítások és az adatbázis újratöltve!' - usage_change_password: 'Használat: "/changepassword <új jelszó>".' - accounts_owned_self: '%count db regisztrációd van:' - accounts_owned_other: 'A %name nevű játékosnak, %count db regisztrációja van:' - -# Session messages -session: - valid_session: '&2A megadott időkereten belül csatlakoztál vissza, így a rendszer automatikusan beléptetett.' - invalid_session: '&cAz IP címed megváltozott, ezért a visszacsatlakozási időkereted lejárt.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Már valaki csatlakozott a szerverhez ezzel az IP címmel!' - same_nick_online: 'Ezzel a játékosnévvel már játszanak a szerveren.' - name_length: '&4A felhasználóneved túl hosszú, vagy túl rövid! Kérlek, válassz másikat!' - characters_in_name: '&4A felhasználóneved nem engedélyezett karaktereket tartalmaz. Engedélyezett karakterek: %valid_chars' - kick_full_server: '&4A szerver megtelt, próbálj csatlakozni később!' - country_banned: '&4Az országod a tiltólistán van ezen a szerveren!' - not_owner_error: 'Ez nem a te felhasználód. Kérlek, válassz másik nevet!' - invalid_name_case: '%valid a felhasználó neved nem? Akkor ne %invalid névvel próbálj feljönni.' - quick_command: 'Túl gyorsan használtad a parancsot! Kérjük, csatlakoz a szerverhez, és várj, amíg bármilyen parancsot használsz.' - -# Email -email: - add_email_request: '&3Kérlek, rendeld hozzá a felhasználódhoz az email címedet "&7/email add &3".' - usage_email_add: '&cHasználat: "&7/email add &c".' - usage_email_change: '&cHasználat: "&7/email change <új email>&c".' - new_email_invalid: '&cHibás az új email cím, próbáld újra!' - old_email_invalid: '&cHibás a régi email cím, próbáld újra!' - invalid: '&cHibás az email cím, próbáld újra!' - added: '&2Az email címed rögzítése sikeresen megtörtént!' - add_not_allowed: '&cAz email hozzáadása nem engedélyezett' - request_confirmation: '&cKérlek, ellenőrízd az email címedet!' - changed: '&2Az email cím cseréje sikeresen megtörtént!' - change_not_allowed: '&cAz emailek módosítása nem engedélyezett' - email_show: '&2A jelenlegi emailed a következő: &f%email' - no_email_for_account: '&2Ehhez a felhasználóhoz jelenleg még nincs email hozzárendelve.' - already_used: '&4Ez az email cím már használatban van!' - incomplete_settings: 'Hiba: nem lett beállítva az összes szükséges beállítás az email küldéshez. Vedd fel a kapcsolatot egy adminnal.' - send_failure: 'Nem sikerült elküldeni az emailt. Lépj kapcsolatba egy adminnal.' - change_password_expired: 'Ezzel a paranccsal már nem módosíthatja jelszavát.' - email_cooldown_error: '&cEgy emailt már kiküldtünk. Következő email küldése előtt várnod kell: %time.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Ha elfelejtetted a jelszavad, használd az "&7/email recovery &3".' - command_usage: '&cHasználat: "&7/email recovery &c".' - email_sent: '&2A jelszó visszaállításhoz szükséges emailt elküldtük! Ellenőrizd a leveleidet!' - code: - code_sent: 'A jelszavad visszaállításához szükséges kódot sikeresen elküldtük az email címedre!' - incorrect: 'A visszaállító kód helytelen volt! Még %count lehetőséged maradt.' - tries_exceeded: 'Elérted a próbálkozások maximális számát. Használd a következő parancsot: "/email recovery [email címed]" egy új generálásához.' - correct: 'A visszaállító kód helyes!' - change_password: 'Használd a következő parancsot: "/email setpassword <új jelszó>", hogy azonnal megváltoztasd a jelszavad.' - -# Captcha -captcha: - usage_captcha: '&3A bejelentkezéshez CAPTCHA szükséges, kérlek, használd a következő parancsot: "&7/captcha %captcha_code&3".' - wrong_captcha: '&cHibás CAPTCHA, kérlek, írd be a következő parancsot: "&7/captcha %captcha_code&c"!' - valid_captcha: '&2A CAPTCHA sikeresen feloldva!' - captcha_for_registration: 'A regisztrációhoz meg kell oldanod a captcha-t, kérjük, használd a parancsot: /captcha %captcha_code' - register_captcha_valid: '&2Érvényes captcha! Most regisztrálhatsz a /register paranccsal.' - -# Verification code -verification: - code_required: '&3Ez a parancs érzékeny, és emailes igazolást igényel! Ellenőrizze a bejövő postafiókot, és kövesse az email utasításait.' - command_usage: '&cHasználat: /verification ' - incorrect_code: '&cHelytelen kód, írd be "/verification " be a chatbe, az emailben kapott kód használatával' - success: '&2Az Ön személyazonosságát ellenőrizték! Mostantól végrehajthatja az összes parancsot az aktuális munkamenetben!' - already_verified: '&2Már minden érzékeny parancsot végrehajthat az aktuális munkameneten belül!' - code_expired: '&3A kód lejárt! Végezzen el egy másik érzékeny parancsot, hogy új kódot kapjon!' - email_needed: '&3A személyazonosságának igazolásához email címet kell csatolnia fiókjához!' - -# Time units -time: - second: 'másodperc' - seconds: 'másodperc' - minute: 'perc' - minutes: 'perc' - hour: 'óra' - hours: 'óra' - day: 'nap' - days: 'nap' - -# Two-factor authentication -two_factor: - code_created: '&2A titkos kódod a következő: %code. Vagy skenneld be a következő oldalról: %url' - confirmation_required: 'Kérjük, erősítsd meg a kódot /2fa confirm ' - code_required: 'Kérjük, küldd el a kétütemű hitelesítési kódot /2fa code ' - already_enabled: 'Kétszámjegyű hitelesítés már engedélyezve van a fiókodban!' - enable_error_no_code: 'Nem hoztad létre a 2fa kulcsot számodra, vagy lejárt. Kérlek, futtasd a /2fa add' - enable_success: 'Sikeresen engedélyezted a fiók kétütemű hitelesítését' - enable_error_wrong_code: 'Hibás kód vagy a kód lejárt. Futtasd a /2fa add' - not_enabled_error: 'Kétszámjegyű hitelesítés nincs engedélyezve a fiókodban. Futtasd a /2fa add' - removed_success: 'Sikeresen eltávolítottad a fiók két számjegyű hitelesítőjét' - invalid_code: 'Érvénytelen kód!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock automatikus bejelentkezés sikeres!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aBeragadtál a portálban a bejelentkezés közben.' - fix_underground: '&aBeragadtál a föld alatt a bejelentkezés közben.' - cannot_fix_underground: '&aBeragadtál a föld alatt a bejelentkezés közben, de nem tudjuk megjavítani.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cKét bejelentkezés miatt lecsatlakoztattak.' diff --git a/src/main/resources/messages/messages_id.yml b/src/main/resources/messages/messages_id.yml deleted file mode 100644 index bf46218f..00000000 --- a/src/main/resources/messages/messages_id.yml +++ /dev/null @@ -1,172 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegister dalam game tidak diaktifkan!' - name_taken: '&cKamu telah mendaftarkan username ini!' - register_request: '&3Silahkan mendaftar ke server menggunakan perintah "/register "' - command_usage: '&cPenggunaan: /register ' - reg_only: '&4Hanya pengguna terdaftar yang bisa bergabung! Silahkan kunjungi https://example.com untuk mendaftar!' - success: '&2Register berhasil!' - kicked_admin_registered: 'Administrator sudah meregistrasi kamu; dimohon untuk login kembali' - -# Password errors on registration -password: - match_error: '&cPassword tidak cocok, silahkan periksa dan ulangi kembali!' - name_in_password: '&cKamu tidak bisa menggunakan namamu sebagai password, silahkan coba yang lain...' - unsafe_password: '&cPassword yang kamu pilih tidak aman, silahkan coba yang lain...' - forbidden_characters: '&4Password kamu memiliki karakter illegal. Karakter yang diperbolehkan: %valid_chars' - wrong_length: '&cPassword kamu terlalu panjang/pendek! Silahkan pilih yang lain!' - -# Login -login: - command_usage: '&cPenggunaan: /login ' - wrong_password: '&cPassword salah!' - success: '&2Login berhasil!' - login_request: '&cSilahkan login menggunakan perintah "/login "' - timeout_error: '&4Jangka waktu login telah habis, kamu dikeluarkan dari server. Silahkan coba lagi!' - -# Errors -error: - denied_command: '&cUntuk menggunakan perintah ini, kamu harus terautentikasi!' - denied_chat: '&cUntuk mengobrol, kamu harus terautentikasi!' - unregistered_user: '&cUser ini belum terdaftar!' - not_logged_in: '&cKamu belum login!' - no_permission: '&4Kamu tidak mempunyai izin melakukan ini!' - unexpected_error: '&4Terjadi kesalahan tak dikenal, silahkan hubungi Administrator!' - max_registration: '&Kamu telah mencapai batas maksimum pendaftaran di server ini!' - logged_in: '&cKamu telah login!' - kick_for_vip: '&3Player VIP mencoba masuk pada saat server sedang penuh!' - kick_unresolved_hostname: '&cTerjadi kesalahan: nama host pemain tidak dapat dipecahkan!' - tempban_max_logins: '&cKamu untuk sementara diblokir karena terlalu sering salah saat login.' - -# AntiBot -antibot: - kick_antibot: 'Proteksi AntiBot diaktifkan! Kamu harus menunggu beberapa menit sebelum masuk server.' - auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak koneksi yg diterima!' - auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!' - -# Unregister -unregister: - success: '&cUnregister berhasil!' - command_usage: '&cPenggunaan: /unregister ' - -# Other messages -misc: - account_not_activated: '&cAkunmu belum diaktifkan, silahkan periksa email kamu!' - not_activated: '&cAkun belum diaktifkan, silakan daftar dan aktivasi sebelum mencoba lagi.' - password_changed: '&2Berhasil mengubah password!' - logout: '&2Berhasil logout!' - reload: '&2Konfigurasi dan database telah dimuat ulang!' - usage_change_password: '&cPenggunaan: /changepassword ' - accounts_owned_self: 'Kamu memiliki %count akun:' - accounts_owned_other: 'Pengguna akun %name memiliki %count akun:' - -# Session messages -session: - valid_session: '&2Otomatis login, karena sesi masih terhubung.' - invalid_session: '&cIP kamu telah berubah, dan sesi kamu telah berakhir!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Seorang pemain dengan IP yang sama sudah didalam permainan!' - same_nick_online: '&4Username yg sama telah bermain di server ini!' - name_length: '&4Username kamu terlalu panjang atau terlalu pendek!' - characters_in_name: '&4Username kamu mengandung karakter illegal. Karakter yg diizinkan: %valid_chars' - kick_full_server: '&4Server sedang penuh, silahkan coba lagi nanti!' - country_banned: '&4Negara kamu diblokir dari server ini!' - not_owner_error: 'Kamu bukan pemilik dari akun ini. Tolong pilih nama lain!' - invalid_name_case: 'Kamu seharusnya masuk menggunakan username %valid, bukan %invalid.' - quick_command: 'Kamu menggunakan perintah terlalu cepat! Tolong masuk kembali ke server dan tunggu sebentar sebelum menggunakan perintah lagi.' - -# Email -email: - add_email_request: '&3Silahkan tambahkan email ke akunmu menggunakan perintah "/email add "' - usage_email_add: '&cPenggunaan: /email add ' - usage_email_change: '&cPenggunaan: /email change ' - new_email_invalid: '&cEmail baru tidak valid, coba lagi!' - old_email_invalid: '&cEmail lama tidak valid, coba lagi!' - invalid: '&cAlamat email tidak valid, coba lagi!' - added: '&2Berhasil menambahkan alamat email ke akunmu!' - add_not_allowed: '&cMenambah email tidak diperbolehkan' - request_confirmation: '&cSilahkan konfirmasi alamat email kamu!' - changed: '&2Alamat email telah diubah dengan benar!' - change_not_allowed: '&cMengubah email tidak diperbolehkan' - email_show: '&2Emailmu saat ini: &f%email' - no_email_for_account: '&2Kamu tidak memiliki alamat email terkait dengan akun ini.' - already_used: '&4Alamat email sudah terpakai' - incomplete_settings: 'Error: tidak semua syarat setelan disetel untuk mengirim email. Tolong kontak Administrator.' - send_failure: 'Email tidak dapat dikirim. Tolong kontak Administrator.' - change_password_expired: 'Kamu tidak dapat mengubah password menggunakan perintah ini lagi.' - email_cooldown_error: '&cSebuah email telah dikirim beberapa waktu lalu. Kamu harus menunggu %time sebelum kamu mengirim yang baru.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Lupa password? silahkan gunakan command "/email recovery "' - command_usage: '&cPenggunaan: /email recovery ' - email_sent: '&2Email pemulihan akun telah dikirim! Silahkan periksa kotak masuk emailmu!' - code: - code_sent: 'Sebuah kode pemulihan untuk mengatur ulang passwordmu telah terkirim ke emailmu.' - incorrect: 'Kode pemulihan salah! Kamu memiliki %count kali kesempatan tersisa.' - tries_exceeded: 'Kamu telah mencapai batas maksimal untuk memasukkan kode pemulihan. Gunakan "/email recovery [email]" membuat yang baru.' - correct: 'Kode pemulihan berhasil dimasukkan!' - change_password: 'Tolong gunakan perintah /email setpassword untuk mengubah passwordmu segera.' - -# Captcha -captcha: - usage_captcha: '&3Kamu harus menyelesaikan kode captcha untuk login, silahkan gunakan perintah "/captcha %captcha_code"' - wrong_captcha: '&cCaptcha salah, gunakan perintah "/captcha %captcha_code" pada komentar!' - valid_captcha: '&2Kode captcha terselesaikan!' - captcha_for_registration: 'Untuk meregistrasi, kamu harus menyelesaikan captcha terlebih dahulu, tolong gunakan perintah: /captcha %captcha_code' - register_captcha_valid: '&2Captcha terselesaikan! Kini kamu dapat mendaftar dengan /register' - -# Verification code -verification: - code_required: '&3Perintah ini sensitif dan memerlukan verifikasi email! Periksa kotak masuk Anda dan ikuti petunjuk email.' - command_usage: '&cPenggunaan: /verification ' - incorrect_code: '&cKode salah, ketik "/verification " di chat, menggunakan kode yang Anda terima melalui email' - success: '&2Identitas Anda telah diverifikasi! Anda sekarang dapat menjalankan semua perintah dalam sesi saat ini!' - already_verified: '&2Anda sudah dapat menjalankan setiap perintah sensitif dalam sesi saat ini!' - code_expired: '&3Kode Anda telah kedaluwarsa! Jalankan perintah sensitif lain untuk mendapatkan kode baru!' - email_needed: '&3Untuk memverifikasi identitas Anda, Anda perlu menyambungkan alamat email dengan akun Anda!!' - -# Time units -time: - second: 'detik' - seconds: 'detik' - minute: 'menit' - minutes: 'menit' - hour: 'jam' - hours: 'jam' - day: 'hari' - days: 'hari' - -# Two-factor authentication -two_factor: - code_created: '&2Kode rahasiamu adalah %code. Kamu dapat memindainya di %url' - confirmation_required: 'Tolong konfirmasi kodemu dengan /2fa confirm ' - code_required: 'Mohon kirimkan kode dari autentikasi dua langkah dengan /2fa code ' - already_enabled: 'Autentikasi dua langkah sudah diaktifkan untuk akunmu!' - enable_error_no_code: 'Tidak ada kunci autentikasi dua langkah atau sudah kadaluarsa. Tolong jalankan /2fa add' - enable_success: 'Sukses mengaktifkan autentikasi dua langkah untuk akunmu' - enable_error_wrong_code: 'Kode salah atau kode sudah kadaluarsa. Tolong jalankan /2fa add' - not_enabled_error: 'Autentikasi dua langkah tidak diaktifkan untuk akunmu. Jalankan /2fa add' - removed_success: 'Sukses menghapus autentikasi dua langkah dari akunmu' - invalid_code: 'Kode tidak valid!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aLogin otomatis Bedrock berhasil!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aAnda terjebak di portal selama proses login.' - fix_underground: '&aAnda terjebak di bawah tanah selama proses login.' - cannot_fix_underground: '&aAnda terjebak di bawah tanah selama proses login, tetapi kami tidak dapat memperbaikinya.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cAnda telah terputus karena login ganda.' diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml deleted file mode 100644 index 53e8afa5..00000000 --- a/src/main/resources/messages/messages_it.yml +++ /dev/null @@ -1,174 +0,0 @@ -# Lingua Italiana creata da Maxetto. -# Tag globali disponibili: -# %nl% - Vai a capo. -# %username% - Sostituisce il nome del giocatore che riceve il messaggio. -# %displayname% - Sostituisce il nickname (e i colori) del giocatore che riceve il messaggio. - -# Registration -registration: - disabled: '&cLa registrazione tramite i comandi di gioco è disabilitata.' - name_taken: '&cHai già eseguito la registrazione!' - register_request: '&3Per favore, esegui la registrazione con il comando: /register ' - command_usage: '&cUtilizzo: /register ' - reg_only: '&4Puoi giocare in questo server solo dopo aver eseguito la registrazione attraverso il sito web! Per favore, vai su https://esempio.it per procedere!' - success: '&2Registrato correttamente!' - kicked_admin_registered: 'Un amministratore ti ha appena registrato, per favore rientra nel server' - -# Password errors on registration -password: - match_error: '&cLe password non corrispondono!' - name_in_password: '&cNon puoi usare il tuo nome utente come password, per favore scegline un''altra...' - unsafe_password: '&cLa password che hai inserito non è sicura, per favore scegline un''altra...' - forbidden_characters: '&4La tua password contiene caratteri non consentiti. I caratteri consentiti sono: %valid_chars' - wrong_length: '&cLa password che hai inserito è troppo corta o troppo lunga, per favore scegline un''altra...' - pwned_password: '&cLa password scelta non è sicura. È stata già utilizzata %pwned_count volte! Si prega di utilizzare una password sicura...' - -# Login -login: - command_usage: '&cUtilizzo: /login ' - wrong_password: '&cPassword non corretta!' - success: '&2Autenticazione eseguita correttamente!' - login_request: '&cPer favore, esegui l''autenticazione con il comando: /login ' - timeout_error: '&4Tempo scaduto per eseguire l''autenticazione, sei stato espulso dal server, per favore riprova!' - -# Errors -error: - denied_command: '&cPer poter usare questo comando devi essere autenticato!' - denied_chat: '&cPer poter scrivere messaggi in chat devi essere autenticato!' - unregistered_user: '&cL''utente non ha ancora eseguito la registrazione.' - not_logged_in: '&cNon hai ancora eseguito l''autenticazione!' - no_permission: '&4Non hai il permesso di eseguire questa operazione.' - unexpected_error: '&4Qualcosa è andato storto, riporta questo errore ad un amministratore!' - max_registration: '&cHai raggiunto il numero massimo di registrazioni (%reg_count/%max_acc %reg_names) per questo indirizzo IP!' - logged_in: '&cHai già eseguito l''autenticazione!' - kick_for_vip: '&3Un giocatore VIP è entrato mentre il server era pieno e ha preso il tuo posto!' - kick_unresolved_hostname: '&cQualcosa è andato storto: hostname del giocatore irrisolvibile!' - tempban_max_logins: '&cSei stato temporaneamente bandito per aver fallito l''autenticazione troppe volte.' - -# AntiBot -antibot: - kick_antibot: 'Il servizio di AntiBot è attualmente attivo! Devi aspettare qualche minuto prima di poter entrare nel server.' - auto_enabled: '&4Il servizio di AntiBot è stato automaticamente abilitato a seguito delle numerose connessioni!' - auto_disabled: '&2Il servizio di AntiBot è stato automaticamente disabilitato dopo %m minuti!' - -# Unregister -unregister: - success: '&2Sei stato correttamente rimosso dal database!' - command_usage: '&cUtilizzo: /unregister ' - -# Other messages -misc: - account_not_activated: '&cIl tuo account non è stato ancora verificato, controlla fra le tue email per scoprire come attivarlo!' - not_activated: '&cAccount non attivato, si prega di registrarsi e attivarlo prima di riprovare.' - password_changed: '&2Password cambiata correttamente!' - logout: '&2Disconnessione avvenuta correttamente!' - reload: '&2La configurazione e il database sono stati ricaricati correttamente!' - usage_change_password: '&cUtilizzo: /changepassword ' - accounts_owned_self: 'Possiedi %count account:' - accounts_owned_other: 'Il giocatore %name possiede %count account:' - -# Session messages -session: - valid_session: '&2Autenticato automaticamente attraverso la precedente sessione!' - invalid_session: '&cIl tuo indirizzo IP è cambiato e la tua sessione è stata terminata!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Un giocatore con il tuo stesso IP è già connesso sul server!' - same_nick_online: '&4Un giocatore con il tuo stesso nome utente è già connesso sul server!' - name_length: '&4Il tuo nome utente è troppo corto o troppo lungo!' - characters_in_name: '&4Il tuo nome utente contiene caratteri non consentiti. I caratteri consentiti sono: %valid_chars' - kick_full_server: '&4Il server è attualmente pieno, riprova più tardi!' - country_banned: '&4Il tuo paese è bandito da questo server!' - not_owner_error: 'Non sei il proprietario di questo account. Per favore scegli un altro nome!' - invalid_name_case: 'Dovresti entrare con questo nome utente "%valid", al posto di "%invalid".' - quick_command: 'Hai usato un comando troppo velocemente dal tuo accesso! Per favore, rientra nel server e aspetta un po'' di più prima di usare un qualsiasi comando.' - -# Email -email: - add_email_request: '&3Per poter recuperare la password in futuro, aggiungi un indirizzo email al tuo account con il comando: /email add ' - usage_email_add: '&cUtilizzo: /email add ' - usage_email_change: '&cUtilizzo: /email change ' - new_email_invalid: '&cIl nuovo indirizzo email inserito non è valido, riprova!' - old_email_invalid: '&cIl vecchio indirizzo email inserito non è valido, riprova!' - invalid: '&cL''indirizzo email inserito non è valido, riprova!' - added: '&2Indirizzo email aggiunto correttamente al tuo account!' - add_not_allowed: '&cNon hai il permesso di aggiungere un indirizzo email' - request_confirmation: '&cPer favore, conferma il tuo indirizzo email!' - changed: '&2Indirizzo email cambiato correttamente!' - change_not_allowed: '&cNon hai il permesso di cambiare l''indirizzo email' - email_show: '&2Il tuo indirizzo email al momento è: &f%email' - no_email_for_account: '&2Al momento non hai nessun indirizzo email associato al tuo account.' - already_used: '&4L''indirizzo email inserito è già in uso' - incomplete_settings: 'Errore: non tutte le impostazioni richieste per inviare le email sono state impostate. Per favore contatta un amministratore.' - send_failure: 'Non è stato possibile inviare l''email di recupero. Per favore contatta un amministratore.' - change_password_expired: 'Non puoi più cambiare la tua password con questo comando.' - email_cooldown_error: '&cUna email di recupero ti è già stata inviata recentemente. Devi attendere %time prima di poterne richiedere una nuova.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Hai dimenticato la tua password? Puoi recuperarla usando il comando: /email recovery ' - command_usage: '&cUtilizzo: /email recovery ' - email_sent: '&2Una email di recupero è stata appena inviata al tuo indirizzo email!' - code: - code_sent: 'Una email contenente il codice di recupero per reimpostare la tua password è stata appena inviata al tuo indirizzo email.' - incorrect: 'Il codice di recupero inserito non è corretto! Hai altri %count tentativi rimanenti.' - tries_exceeded: 'Hai superato il numero massimo di tentativi per inserire il codice di recupero. Scrivi "/email recovery [email]" per generarne uno nuovo.' - correct: 'Codice di recupero inserito correttamente!' - change_password: 'Per favore usa il comando "/email setpassword " per cambiare immediatamente la tua password.' - -# Captcha -captcha: - usage_captcha: '&3Per poterti autenticare devi risolvere un captcha, per favore scrivi: /captcha %captcha_code' - wrong_captcha: '&cCaptcha sbagliato, per favore riprova scrivendo "/captcha %captcha_code" in chat!' - valid_captcha: '&2Il captcha inserito è valido!' - captcha_for_registration: 'Per poterti registrare devi prima risolvere un captcha, per favore scrivi: /captcha %captcha_code' - register_captcha_valid: '&2Il captcha inserito è valido! Ora puoi eseguire la registrazione con: /register ' - -# Verification code -verification: - code_required: '&3Questo comando va a modificare dati sensibili e richiede una verifica tramite email! Controlla la tua posta in arrivo e segui le istruzioni nell''email.' - command_usage: '&cUtilizzo: /verification ' - incorrect_code: '&cCodice sbagliato, per favore riprova scrivendo "/verification " in chat, usando il codice che hai ricevuto tramite email' - success: '&2La tua identità è stata verificata! Ora puoi eseguire tutti i comandi che modificano dati sensibili per questa sessione!' - already_verified: '&2Puoi già eseguire tutti i comandi che modificano dati sensibili per questa sessione!' - code_expired: '&3Il tuo codice è scaduto! Esegui nuovamente un comando che modifica dati sensibili per ricevere uno nuovo codice!' - email_needed: '&3Per verificare la tua identità devi collegare un indirizzo email al tuo account!' - -# Time units -time: - second: 'secondo' - seconds: 'secondi' - minute: 'minuto' - minutes: 'minuti' - hour: 'ora' - hours: 'ore' - day: 'giorno' - days: 'giorni' - -# Two-factor authentication -two_factor: - code_created: '&2Il tuo codice segreto è: &f%code%%nl%&2Puoi anche scannerizzare il codice QR da qui: &f%url' - confirmation_required: 'Per favore conferma il tuo codice con: /2fa confirm ' - code_required: 'Per favore inserisci il tuo codice per l''autenticazione a 2 fattori con: /2fa code ' - already_enabled: 'Hai già abilitato l''autenticazione a 2 fattori!' - enable_error_no_code: 'Non hai ancora generato un codice per l''autenticazione a 2 fattori oppure il tuo codice è scaduto. Per favore scrivi: /2fa add' - enable_success: 'Autenticazione a 2 fattori abilitata correttamente' - enable_error_wrong_code: 'Hai inserito un codice sbagliato o scaduto. Per favore scrivi: /2fa add' - not_enabled_error: 'L''autenticazione a 2 fattori non è ancora abilitata per il tuo account. Scrivi: /2fa add' - removed_success: 'Autenticazione a 2 fattori rimossa correttamente' - invalid_code: 'Il codice inserito non è valido, riprova!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aAccesso automatico Bedrock riuscito!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aSei bloccato nel portale durante il login.' - fix_underground: '&aSei bloccato sottoterra durante il login.' - cannot_fix_underground: '&aSei bloccato sottoterra durante il login, ma non possiamo risolverlo.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cSei stato disconnesso a causa di un login doppio.' diff --git a/src/main/resources/messages/messages_ja.yml b/src/main/resources/messages/messages_ja.yml deleted file mode 100644 index ac846a25..00000000 --- a/src/main/resources/messages/messages_ja.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cゲーム内での登録は無効になっています!' - name_taken: '&cこのユーザー名はすでに登録されています!' - register_request: '&3サーバーに登録するには、次のコマンドを使用してください: /register <パスワード> <パスワードの確認>' - command_usage: '&c使用方法: /register <パスワード> <パスワードの確認>' - reg_only: '&4登録済みのユーザーのみサーバーに参加できます! 自分自身を登録するには、https://example.com にアクセスしてください!' - success: '&2登録が完了しました!' - kicked_admin_registered: '管理者があなたを登録しました。再度ログインしてください。' - -# Password errors on registration -password: - match_error: '&cパスワードが一致しません。もう一度確認してください!' - name_in_password: '&cパスワードには自分の名前を使用することはできません。別のパスワードを選択してください...' - unsafe_password: '&c選択したパスワードは安全ではありません。別のパスワードを選択してください...' - forbidden_characters: '&4パスワードに不正な文字が含まれています。許可されている文字: %valid_chars' - wrong_length: '&cパスワードが短すぎるか長すぎます!別のパスワードを試してください!' - pwned_password: '&c選択されたパスワードは安全ではありません。すでに %pwned_count 回使用されています!強力なパスワードを使用してください...' - -# Login -login: - command_usage: '&c使用方法: /login <パスワード>' - wrong_password: '&cパスワードが間違っています!' - success: '&2ログインが成功しました!' - login_request: '&c次のコマンドを使用してログインしてください: /login <パスワード>' - timeout_error: '&4ログインのタイムアウトが発生しました。サーバーからキックされました。もう一度試してください!' - -# Errors -error: - denied_command: '&cこのコマンドを使用するには認証が必要です!' - denied_chat: '&cチャットするには認証が必要です!' - unregistered_user: '&cこのユーザーは登録されていません!' - not_logged_in: '&cログインしていません!' - no_permission: '&4この操作を実行する権限がありません!' - unexpected_error: '&4予期しないエラーが発生しました。管理者に連絡してください!' - max_registration: '&c接続ごとの登録数が最大値を超えています(%reg_count/%max_acc %reg_names)!' - logged_in: '&cすでにログイン済みです!' - kick_for_vip: '&3VIPプレイヤーがサーバーが満員の状態で参加しました!' - kick_unresolved_hostname: '&cエラーが発生しました:解決できないプレイヤーのホスト名!' - tempban_max_logins: '&cログインに失敗した回数が多すぎるため、一時的にアクセスが制限されています。' - -# AntiBot -antibot: - kick_antibot: 'AntiBot保護モードが有効です!サーバーに参加するまでにしばらくお待ちください。' - auto_enabled: '&4[AntiBotService] 接続数が非常に多いため、AntiBotが有効になりました!' - auto_disabled: '&2[AntiBotService] %m 分後にAntiBotが無効になりました!' - -# Unregister -unregister: - success: '&c登録が正常に解除されました!' - command_usage: '&c使用方法: /unregister <パスワード>' - -# Other messages -misc: - account_not_activated: '&cアカウントはまだ有効化されていません。メールを確認してください!' - not_activated: '&cアカウントは有効化されていません。再試行する前に登録してアクティブ化してください。' - password_changed: '&2パスワードが正常に変更されました!' - logout: '&2正常にログアウトしました!' - reload: '&2設定とデータベースが正常に再読み込みされました!' - usage_change_password: '&c使用方法: /changepassword <旧パスワード> <新パスワード>' - accounts_owned_self: '所持しているアカウント数:%count 個' - accounts_owned_other: 'プレイヤー %name のアカウント数:%count 個' - -# Session messages -session: - valid_session: '&2セッションの再接続によるログインです。' - invalid_session: '&cIPアドレスが変更され、セッションのデータが期限切れです!' - -# Error messages when joining -on_join_validation: - same_ip_online: '同じIPアドレスを持つプレイヤーが既にゲーム内にいます!' - same_nick_online: '&4同じユーザー名のプレイヤーが既にサーバーでプレイしています!' - name_length: '&4ユーザー名が短すぎるか長すぎます!' - characters_in_name: '&4ユーザー名に無効な文字が含まれています。許可される文字:%valid_chars' - kick_full_server: '&4サーバーが満員です。後でもう一度お試しください!' - country_banned: '&4このサーバーへのアクセスは、お使いの国から制限されています!' - not_owner_error: 'このアカウントの所有者ではありません。別の名前を選択してください!' - invalid_name_case: '正しいユーザー名は %valid です。%invalid ではなく、このユーザー名で参加してください。' - quick_command: 'コマンドを速すぎる速度で使用しました!もう一度サーバーに参加してから、コマンドを使用する前にしばらくお待ちください。' - -# Email -email: - add_email_request: '&3コマンド「/email add <あなたのメールアドレス> <確認用メールアドレス>」を使用して、アカウントにメールアドレスを追加してください。' - usage_email_add: '&c使用方法:/email add <メールアドレス> <メールアドレスの確認>' - usage_email_change: '&c使用方法:/email change <古いメールアドレス> <新しいメールアドレス>' - new_email_invalid: '&c無効な新しいメールアドレスです。もう一度やり直してください!' - old_email_invalid: '&c無効な古いメールアドレスです。もう一度やり直してください!' - invalid: '&c無効なメールアドレスです。もう一度やり直してください!' - added: '&2メールアドレスがアカウントに正常に追加されました!' - add_not_allowed: '&cメールアドレスの追加は許可されていません。' - request_confirmation: '&cメールアドレスを確認してください!' - changed: '&2メールアドレスが正しく変更されました!' - change_not_allowed: '&cメールアドレスの変更は許可されていません。' - email_show: '&2現在のメールアドレスは:%email' - no_email_for_account: '&2現在、このアカウントに関連付けられたメールアドレスはありません。' - already_used: '&4そのメールアドレスは既に使用されています' - incomplete_settings: 'エラー:メールの送信に必要なすべての設定が設定されていません。管理者に連絡してください。' - send_failure: 'メールを送信できませんでした。管理者に連絡してください。' - change_password_expired: 'このコマンドを使用してパスワードを変更することはできません。' - email_cooldown_error: '&c最近すでにメールが送信されています。新しいメールを送信する前に、%time 待つ必要があります。' - -# Password recovery by email -recovery: - forgot_password_hint: '&3パスワードを忘れましたか?次のコマンドを使用してください:/email recovery <あなたのメールアドレス>' - command_usage: '&c使用方法:/email recovery <メールアドレス>' - email_sent: '&2パスワードの回復メールが正常に送信されました!メールの受信トレイを確認してください!' - code: - code_sent: 'パスワードをリセットするための回復コードがメールで送信されました。' - incorrect: '回復コードが正しくありません!残りの試行回数:%count' - tries_exceeded: '回復コードの入力試行回数が上限を超えました。新しいコードを生成するには、"/email recovery [メールアドレス]" を実行してください。' - correct: '回復コードが正しく入力されました!' - change_password: '即座にパスワードを変更するには、コマンド「/email setpassword <新しいパスワード>」を使用してください。' - -# Captcha -captcha: - usage_captcha: '&3ログインするには、Captchaコードを解決する必要があります。次のコマンドを使用してください:/captcha %captcha_code' - wrong_captcha: '&cCaptchaコードが間違っています。チャットに「/captcha %captcha_code」と入力してください!' - valid_captcha: '&2Captchaコードが正しく解決されました!' - captcha_for_registration: '登録するには、まずCaptchaを解決する必要があります。次のコマンドを使用してください:/captcha %captcha_code' - register_captcha_valid: '&2有効なCaptchaです!/register を使用して登録できます' - -# Verification code -verification: - code_required: '&3このコマンドはセンシティブな操作であり、メールの認証が必要です!受信トレイを確認し、メールの指示に従ってください。' - command_usage: '&c使用方法:/verification <コード>' - incorrect_code: '&cコードが正しくありません。メールで受け取ったコードを使用して、「/verification <コード>」とチャットに入力してください。' - success: '&2身元が確認されました!現在のセッション内ですべてのコマンドを実行できます!' - already_verified: '&2現在のセッションでは、既にすべてのセンシティブなコマンドを実行できます!' - code_expired: '&3コードの有効期限が切れています!新しいコードを取得するには、別のセンシティブなコマンドを実行してください!' - email_needed: '&3アカウントにはメールアドレスのリンクが必要です。身元を確認するためにはメールアドレスを関連付けてください!' - -# Time units -time: - second: '秒' - seconds: '秒' - minute: '分' - minutes: '分' - hour: '時間' - hours: '時間' - day: '日' - days: '日' - -# Two-factor authentication -two_factor: - code_created: '&2秘密コードは %code です。こちらからスキャンできます:%url' - confirmation_required: 'コードを確認するには、/2fa confirm <コード> を使用してください' - code_required: '二要素認証コードを提出するには、/2fa code <コード> を使用してください' - already_enabled: 'アカウントで既に二要素認証が有効になっています!' - enable_error_no_code: '2要素認証キーが生成されていないか、期限が切れています。/2fa add を実行してください' - enable_success: 'アカウントでの二要素認証が正常に有効になりました' - enable_error_wrong_code: 'コードが間違っているか、期限が切れています。/2fa add を実行してください' - not_enabled_error: 'アカウントでは二要素認証が有効になっていません。/2fa add を実行してください' - removed_success: 'アカウントから二要素認証が正常に削除されました' - invalid_code: '無効なコードです!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock 自動ログイン成功!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aログイン中にポータルに閉じ込められました。' - fix_underground: '&aログイン中に地下に閉じ込められました。' - cannot_fix_underground: '&aログイン中に地下に閉じ込められましたが、修正できません。' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&c二重ログインのため、切断されました。' diff --git a/src/main/resources/messages/messages_ko.yml b/src/main/resources/messages/messages_ko.yml deleted file mode 100644 index 6354fdf4..00000000 --- a/src/main/resources/messages/messages_ko.yml +++ /dev/null @@ -1,175 +0,0 @@ -#Translated by Kirito (kds123321@naver.com), Spectre (me@ptr.kr), Adeuran(adeuran@tistory.com) -#14.05.2017 Thanks for use -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&c현재 회원 가입이 비활성화 되어 있습니다!' - name_taken: '&c이미 이 닉네임으로 회원 가입이 되어 있습니다!' - register_request: '&3다음 명령어로 서버에 가입해주세요: /register <비밀번호> <비밀번호 확인>' - command_usage: '&c사용법: /register <비밀번호> <비밀번호 확인>' - reg_only: '&4등록된 유저만 서버에 접속할 수 있습니다! 서버 홈페이지에 방문하여 가입해 주세요!' - success: '&2회원 가입이 완료되었습니다!' - kicked_admin_registered: '관리자가 방금 이 닉네임을 등록했습니다. 다시 로그인 해주세요' - -# Password errors on registration -password: - match_error: '&c비밀번호가 일치하지 않습니다, 다시 확인해주세요!' - name_in_password: '&c자신의 닉네임을 비밀번호로 사용할 수 없습니다, 다른 비밀번호를 사용하세요...' - unsafe_password: '&c이 비밀번호는 안전하지 않습니다, 다른 비밀번호를 사용하세요...' - forbidden_characters: '&4비밀번호에 잘못된 문자가 있습니다. 허용된 문자: %valid_chars' - wrong_length: '&c비밀번호가 너무 짧거나 너무 깁니다!' - pwned_password: '&c선택한 비밀번호가 안전하지 않습니다. 이미 %pwned_count 번 사용되었습니다! 강력한 비밀번호를 사용하세요...' - -# Login -login: - command_usage: '&c사용법: /login <비밀번호>' - wrong_password: '&c비밀번호가 잘못되었습니다!' - success: '&2로그인 되었습니다!' - login_request: '&c다음 명령어로 로그인 해주세요: /login <비밀번호>' - timeout_error: '&4로그인 시간이 초과 되어 서버에서 추방당했습니다. 다시 시도하세요!' - -# Errors -error: - denied_command: '&c이 명령어를 사용하려면 로그인해야 합니다!' - denied_chat: '&c채팅을 하려면 로그인해야 합니다!' - unregistered_user: '&c이 유저는 등록되지 않았습니다!' - not_logged_in: '&c로그인이 되어있지 않습니다!' - no_permission: '&4이 작업을 수행할 수 있는 권한이 없습니다!' - unexpected_error: '&4예기치 않은 오류가 발생했습니다, 관리자에게 알려주세요!' - max_registration: '&c당신은 가입할 수 있는 계정 한도를 초과했습니다 (%reg_count/%max_acc %reg_names)!' - logged_in: '&c이미 로그인되어 있습니다!' - kick_for_vip: '&3서버가 꽉 차있을 때는 VIP 플레이어만 접속이 가능합니다!' - kick_unresolved_hostname: '&c오류 발생: 확인되지 않은 플레이어 호스트 이름!' - tempban_max_logins: '&c너무 많이 로그인에 실패하여 잠시 서버에서 차단되었습니다.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot 보호 모드가 활성화 되었습니다! 서버에 접속하려면 몇 분 기다려야 합니다.' - auto_enabled: '&4[AntiBotService] 엄청나게 많은 연결이 감지 되어 AntiBot이 활성화 되었습니다!' - auto_disabled: '&2[AntiBotService] %m 분 후에 AntiBot이 비활성화 됩니다!' - -# Unregister -unregister: - success: '&c회원 탈퇴가 완료되었습니다!' - command_usage: '&c사용법: /unregister <비밀번호>' - -# Other messages -misc: - account_not_activated: '&c계정이 아직 활성화되지 않았습니다. 이메일을 확인해보세요!' - not_activated: '&c계정이 활성화되지 않았습니다. 다시 시도하기 전에 등록하고 활성화하세요.' - password_changed: '&2비밀번호가 변경되었습니다!' - logout: '&2로그아웃 되었습니다!' - reload: '&2설정과 데이터 베이스가 새로고침 되었습니다!' - usage_change_password: '&c사용법: /changepassword <예전 비밀번호> <새 비밀번호>' - accounts_owned_self: '%count 개의 계정을 소유하고 있습니다.' - accounts_owned_other: '플레이어 %name 는 %count 개의 계정을 소유하고 있습니다:' - -# Session messages -session: - valid_session: '&2세션 재 연결로 인해 로그인 되었습니다.' - invalid_session: '&cIP가 변경되어 세션이 만료되었습니다!' - -# Error messages when joining -on_join_validation: - same_ip_online: '똑같은 IP가 이미 이 서버에 접속해 있습니다!' - same_nick_online: '&4똑같은 닉네임이 이미 이 서버에 접속해 있습니다!' - name_length: '&4닉네임이 너무 짧거나 너무 깁니다!' - characters_in_name: '&4닉네임에 잘못된 문자가 있습니다. 허용된 문자: %valid_chars' - kick_full_server: '&4서버가 꽉 찼습니다. 나중에 다시 접속해보세요!' - country_banned: '&4당신의 국가에서는 이 서버를 이용하실 수 없습니다!' - not_owner_error: '이 계정의 소유자가 아닙니다. 다른 닉네임을 선택하세요!' - invalid_name_case: '%invalid가 아닌, %valid 사용하여 접속해야 합니다.' - quick_command: '명령어를 너무 빠르게 입력하고 있습니다! 서버에 다시 접속한 후 조금만 기다려주시기 바랍니다.' - -# Email -email: - add_email_request: '&3다음 명령어로 계정에 이메일 주소를 추가하세요: /email add <이메일 주소> <이메일 주소 확인>' - usage_email_add: '&c사용법: /email add <이메일 주소> <이메일 주소 확인>' - usage_email_change: '&c사용법: /email change <예전 이메일 주소> <새 이메일 주소>' - new_email_invalid: '&c새 이메일 주소가 잘못되었습니다. 다시 시도해보세요!' - old_email_invalid: '&c예전 이메일 주소가 잘못되었습니다. 다시 시도해보세요!' - invalid: '&c이메일 주소가 잘못되었습니다. 다시 시도해보세요!' - added: '&2계정에 이메일 주소를 추가했습니다!' - add_not_allowed: '&c이메일 주소의 추가가 제한된 상태입니다.' - request_confirmation: '&c이메일 주소를 확인해주세요!' - changed: '&2이메일 주소가 변경되었습니다!' - change_not_allowed: '&c이메일 주소의 변경이 제한된 상태입니다.' - email_show: '&2현재 이메일 주소: &f%email' - no_email_for_account: '&2현재 이 계정과 연결된 이메일 주소가 없습니다.' - already_used: '&4이메일 주소가 이미 사용 중입니다.' - incomplete_settings: '오류: 메일을 보내기 위해 필요한 설정이 되어 있지 않습니다. 관리자에게 알려주세요.' - send_failure: '이메일을 보낼 수 없습니다. 관리자에게 알려주세요.' - change_password_expired: '더 이상 이 명령어를 통해 비밀번호를 변경할 수 없습니다.' - email_cooldown_error: '&c이메일을 이미 발송했습니다. %time 후에 다시 발송할 수 있습니다.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3비밀번호를 잊으셨나요? 이 명령어를 사용해보세요: /email recovery <이메일 주소>' - command_usage: '&c사용법: /email recovery <이메일 주소>' - email_sent: '&2복구 이메일을 보냈습니다! 메일함을 확인해보세요!' - code: - code_sent: '비밀번호 재설정을 위한 복구 코드가 이메일로 전송되었습니다.' - incorrect: '복구 코드가 올바르지 않습니다! "/email recovery [이메일 주소]"를 이용하여 새로 생성하세요.' - tries_exceeded: '잘못된 복구 코드를 너무 많이 입력했습니다. "/email recovery [이메일 주소]"를 통해 새로 생성하세요.' - correct: '복구 코드가 정상적으로 입력되었습니다!' - change_password: '비밀번호를 변경하려면 /email setpassword <새 비밀번호>를 입력해주세요.' - -# Captcha -captcha: - usage_captcha: '&3로그인 하려면 CAPTCHA 코드를 입력해야 합니다. 이 명령어를 사용하세요: /captcha %captcha_code' - wrong_captcha: '&c잘못된 CAPTCHA 코드 입니다. "/captcha %captcha_code" 형태로 입력해주세요!' - valid_captcha: '&2CAPTCHA 코드가 확인되었습니다!' - captcha_for_registration: '회원 가입을 하기 위해서는 먼저 CAPTCHA 코드를 입력해야합니다. 이 명령어를 이 명령어를 사용하세요: /captcha %captcha_code' - register_captcha_valid: '&2올바른 CAPTCHA 코드입니다! 이제 /register 명령어를 이용하여 회원 가입할 수 있습니다.' - -# Verification code -verification: - code_required: '&3이 명령어는 매우 민감하게 작동되며, 이메일 인증을 필요로 합니다. 이메일을 확인하고 지시에 따르십시오.' - command_usage: '&c사용법: /verification <인증 코드>' - incorrect_code: '&c코드가 올바르지 않습니다. "/verification <인증 코드>" 형태로 입력해주세요.' - success: '&2신원이 확인되었습니다. 귀하는 이 세션이 만료되기 전까지 모든 명령어를 사용할 수 있습니다.' - already_verified: '&2이 인증 코드는 이미 사용되었습니다!' - code_expired: '&3이 인증 코드는 만료되었습니다! 새 인증 코드를 발급받아주세요.' - email_needed: '&3귀하의 신원을 확인하기 위해서는 귀하의 계정과 이메일 주소가 연결되어 있어야 합니다.' - -# Time units -time: - second: '초' - seconds: '초' - minute: '분' - minutes: '분' - hour: '시간' - hours: '시간' - day: '일' - days: '일' - -# Two-factor authentication -two_factor: - code_created: '&2당신의 2단계 인증 코드는 %code 입니다. %url 에서 스캔할 수 있습니다' - confirmation_required: '/2fa confirm 명령어를 통해 귀하의 코드를 확인해 주시기 바랍니다.' - code_required: '/2fa code 명령어를 통해 2단계 인증을 진행해주세요.' - already_enabled: '2단계 인증 기능을 이미 활성화하셨습니다!' - enable_error_no_code: '2단계 인증 키가 생성되지 않았거나 만료되었습니다. /2fa add 명령어를 통해 새로 생성해주세요.' - enable_success: '2단계 인증 기능을 성공적으로 활성화하였습니다.' - enable_error_wrong_code: '잘못되었거나 만료된 코드입니다. /2fa add 명령어를 통해 새로 생성해주세요.' - not_enabled_error: '2단계 인증 기능을 활성화하시지 않았습니다. /2fa add 명령어를 통해 활성화해주세요.' - removed_success: '2단계 인증 기능을 성공적으로 비활성화하였습니다.' - invalid_code: '올바르지 않은 인증 코드입니다!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock 자동 로그인 성공!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&a로그인 중에 포탈에 갇혔습니다.' - fix_underground: '&a로그인 중에 지하에 갇혔습니다.' - cannot_fix_underground: '&a로그인 중에 지하에 갇혔지만, 수정할 수 없습니다.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&c중복 로그인으로 인해 연결이 종료되었습니다.' diff --git a/src/main/resources/messages/messages_lt.yml b/src/main/resources/messages/messages_lt.yml deleted file mode 100644 index b09bbb64..00000000 --- a/src/main/resources/messages/messages_lt.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&6Registracija yra išjungta' - name_taken: '&cVartotojo vardas jau užregistruotas' - register_request: '&ePrašome prisiregistruoti: /register slaptažodis pakartotiSlaptažodį' - command_usage: '&eNaudojimas: /register slaptažodis pakartotiSlaptažodį' - reg_only: '&cTik prisiregistravusiems žaidėjams: apsilankykite: https://example.com tam, kad užsiregistruoti.' - success: '&aSėkmingai prisiregistravote.' - kicked_admin_registered: 'Administatorius Jus užregistravo. Prisijunkite iš naujo' - -# Password errors on registration -password: - match_error: '&cSlaptažodžiai nesutampa' - name_in_password: '&cJūs negalite naudoti savo vardo slaptažodyje' - unsafe_password: '&cŠį Slaptažodį lengva nulaužti, pasirinkite kitą slaptažodį' - forbidden_characters: '&4Jūsų slaptažodis turi netinkamų simbolių. Leidžiami simboliai: %valid_chars' - wrong_length: '&cJūsų pasirinktas slaptažodis per ilgas arba per trumpas.' - pwned_password: '&cJūsų pasirinktas slaptažodis nėra saugus. Jis buvo naudotas %pwned_count kartų! Prašome naudoti stiprų slaptažodį...' - -# Login -login: - command_usage: '&eKomandos panaudojimas: /login slaptažodis' - wrong_password: '&cNeteisingas Slaptažosdis' - success: '&aSėkmingai prisijungėte' - login_request: '&ePrašome prisijungti: /login slaptažodis' - timeout_error: '&cNespėjote prisijungti' - -# Errors -error: - denied_command: '&cKad galetumėte naudoti šią komandą turite būti prisijungę!' - denied_chat: '&cKad galetumėte kalbėti Jūs turite būti prisijungę!' - unregistered_user: '&cVartotojas neprisiregistravęs' - not_logged_in: '&cJūs neprisijungę!' - no_permission: '&cNėra leidimo' - unexpected_error: '&cAtsirado klaida, praneškite adminstratoriui.' - max_registration: '&cJūs pasiekėte maksimalų registracijų skaičių.' - logged_in: '&cTu jau prisijungęs!' - kick_for_vip: '&cRėmėjas prisijungė į pilną serverį!' - kick_unresolved_hostname: '&cĮvyko klaida su žaidejo adresu!' - tempban_max_logins: '&cJūs laikinai užblokuotas, nes kelis kartus neteisingai suvedėte slaptažodį.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot prevencija įjungta! Palaukite prieš prisijungiant.' - auto_enabled: '&4[AntiBotService] AntiBot prevencija pajungta dėl didelio kiekio prisijungimų!' - auto_disabled: '&2[AntiBotService] AntiBot bus išjungtas po %m minučių!' - -# Unregister -unregister: - success: '&aSėkmingai išsiregistravote!' - command_usage: '&ePanaikinti registraciją: "/unregister slaptažodis"' - -# Other messages -misc: - account_not_activated: '&aJūsų vartotojas nėra patvirtintas, pasitikrinkite el.paštą.' - not_activated: '&cPaskyra neaktyvuota, prašome užsiregistruoti ir aktyvuoti prieš bandant dar kartą.' - password_changed: '&aSlaptažodis pakeistas' - logout: '&aSėkmingai atsijungėte' - reload: '&aNustatymai ir duomenų bazė buvo perkrauta.' - usage_change_password: '&ePanaudojimas: /changepassword senasSlaptažodis naujasSlaptažodis' - accounts_owned_self: 'Jūs turite %count paskyrą(-s):' - accounts_owned_other: 'Žaidejas %name turi %count paskyrą(-s):' - -# Session messages -session: - valid_session: '&aAutomatinis sesijos prisijungimas' - invalid_session: '&cSesijos laikai nesutampa. Prašome palaukti kol sesija baigsis.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Žaidejas su tuo pačiu IP adresu jau yra žaidime!' - same_nick_online: '&cKažkas šituo vardu jau žaidžia.' - name_length: '&cJūsų vardas yra per ilgas arba per trumpas.' - characters_in_name: '&cJūsų varde yra neledziamų simbolių. Leidžiami: %valid_chars' - kick_full_server: '&cServeris yra pilnas, atsiprašome.' - country_banned: '&4Jūsų šalis yra užblokuota šiame serveryje!' - not_owner_error: 'J0s nesate šios paskyros savininkas, pasirinkite kitą vardą!' - invalid_name_case: 'Turėtumėte prisijungti su vardu %valid, o ne su: %invalid.' - quick_command: 'Jūs panaudojote komandą per greitai! Prisijunkite iš naujo ir šiek tiek palaukite prieš naudojant komandas.' - -# Email -email: - add_email_request: '&ePrašome jūsų pridėti savo el.paštą : /email add ' - usage_email_add: '&cNaudojimas: /email add ' - usage_email_change: '&cNaudojimas: /email change ' - new_email_invalid: '&cNeteisingas el.paštas, bandykite iš naujo!' - old_email_invalid: '&cNeteisingas senas el.paštas, bandykite iš naujo!' - invalid: '&cNeteisingas el.paštas, bandykite iš naujo!' - added: '&2El.paštas sėkmingai pridėtas!' - add_not_allowed: '&cNaujo el.pašto pridejimas nėra galimas' - request_confirmation: '&cPatvirtinkite savo el.paštą!' - changed: '&2El.paštą pakeistas sėkmingai!' - change_not_allowed: '&cEl.pašto keitimas nėra galimas' - email_show: '&2Jūsų dabartinis el.pašto adresas: &f%email' - no_email_for_account: '&2Šiuo metu Jūs neturite pridėję jokio el.pašto adreso.' - already_used: '&4Jis el.pašto adresas jau yra naudojamas' - incomplete_settings: 'Klaida: Ne visi nustatymai yra nustatyti laiško siuntimui. Susikietite su administratoriumi.' - send_failure: 'El.pašto laiškas nebuvo išsiųstas. Susikietite su administratoriumi.' - change_password_expired: 'Jūs nebegalite pakeisti savo slaptažodzio naudojant šią komandą.' - email_cooldown_error: '&cEl.pašto laiškas jau buvo išsiųstas. Palaukite %time prieš šiunčiant naują.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cPamiršote savo slaptažodį? Rašykite: /email recovery el.paštas' - command_usage: '&cNaudojimas: /email recovery el.paštas' - email_sent: '&2Laiškas į Jūsų el.pašto adresą buvo išsiųstas!' - code: - code_sent: 'Kodas slaptažodžio atstatymui buvo išsiųstas į Jūsų el.paštą.' - incorrect: 'Kodas neteisingas! Jums liko %count bandymai(-as).' - tries_exceeded: 'Jūs išnaudojote visus bandymus. Naudokite "/email recovery el.paštas", kad gauti naują kodą.' - correct: 'Kodas įvestas sėkmingai!' - change_password: 'Naudokite /email setpassword , kad pasikeistumėte slaptažodį.' - -# Captcha -captcha: - usage_captcha: '&cPanaudojimas: /captcha %captcha_code' - wrong_captcha: '&cNeteisinga captcha, naudokite : /captcha %captcha_code' - valid_captcha: '&cJūsų captcha teisinga!' - captcha_for_registration: 'Kad prisiregistruotumėte turite įvygdyti captchą. Rašykite: /captcha %captcha_code' - register_captcha_valid: '&2Captcha teisinga! Galite naudoti /register' - -# Verification code -verification: - code_required: '&3Kad galėtumėte naudoti šią komandą turite patvirtinti savo el.pašto adresą! Sekite instrukcijas savo el.pašte.' - command_usage: '&cNaudojimas: /verification ' - incorrect_code: '&cNeteisingas kodas, naudokite "/verification " įvesdami kodą gautą savo el.pašte' - success: '&2Jūsų paskyra patvirtinta! Jūs galite naudoti visas komandas!' - already_verified: '&2Jūs jau esate patvirtinę savo paskyrą ir galite naudoti visas komandas!' - code_expired: '&3Jūsų kodo galiojimas baigėsi! Panaudokite komandą iš naujo, kad gautumėte naują kodą!' - email_needed: '&3Kad patvirtinti savo paskyra turite pridėti el.pašto adresą!' - -# Time units -time: - second: 'sekundę' - seconds: 'sekundes' - minute: 'minutę' - minutes: 'minutes' - hour: 'valandą' - hours: 'valandas' - day: 'dieną' - days: 'dienas' - -# Two-factor authentication -two_factor: - code_created: '&2Jūsų slaptas kodas yra %code. Jį galite nuskenuoti čia: %url' - confirmation_required: 'Patvirtinkite savo kodą su: /2fa confirm ' - code_required: 'Patvirkinkite savo kodą su: /2fa code ' - already_enabled: 'Jūs jau turite dviejų faktorių autentifikaciją!' - enable_error_no_code: 'Jūs neturite dviejų faktorių autentifikacijos arba ji pasibaigė. Rašykite /2fa add' - enable_success: 'Dviejų faktorių autentifikacija sėkmingai įjungta' - enable_error_wrong_code: 'Neteisingas arba pasibaigęs kodas. Rašykite /2fa add' - not_enabled_error: 'Dviejų faktorių autentifikavimas nėra įjungtas ant jūsų paskyros. Rašykite /2fa add' - removed_success: 'Dviejų faktorių autentifikavimas sėkmingai pašalintas iš jūsų paskyros.' - invalid_code: 'Neteisingas kodas!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock automatinis prisijungimas sėkmingas!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aJūs užstrigote portale prisijungimo metu.' - fix_underground: '&aJūs užstrigote po žeme prisijungimo metu.' - cannot_fix_underground: '&aJūs užstrigote po žeme prisijungimo metu, bet mes negalime to pataisyti.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cJūs buvote atjungtas dėl dvigubo prisijungimo.' diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml deleted file mode 100644 index 42c3207c..00000000 --- a/src/main/resources/messages/messages_nl.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegistratie is uitgeschakeld!' - name_taken: '&cJe hebt deze gebruikersnaam al geregistreerd!' - register_request: '&cRegistreer met het commando: /register ' - command_usage: '&cGebruik: /register ' - reg_only: 'Alleen voor geregistreerde spelers! Bezoek https://example.com om te registreren!' - success: '&cSuccesvol geregistreerd!' - kicked_admin_registered: 'Een administrator heeft je net geregistreerd; log alsjeblieft opnieuw in.' - -# Password errors on registration -password: - match_error: 'Jouw wachtwoorden komen niet overeen, controleer ze opnieuw!' - name_in_password: '&fJe kunt je gebruikersnaam niet als wachtwoord gebruiken, kies een ander wachtwoord...' - unsafe_password: '&fDit wachtwoord is onveilig, kies een ander wachtwoord...' - forbidden_characters: '&cJouw wachtwoord bevat ongeldige tekens. Toegestane karakters zijn: %valid_chars' - wrong_length: 'Jouw gekozen wachtwoord voldoet niet aan de minimum of maximum lengte, kies een ander wachtwoord...' - pwned_password: '&cHet gekozen wachtwoord is niet veilig. Het is al %pwned_count keer gebruikt! Gebruik alstublieft een sterk wachtwoord...' - -# Login -login: - command_usage: '&cGebruik: /login ' - wrong_password: '&cFout wachtwoord' - success: '&cSuccesvol ingelogd!' - login_request: '&cLog in met: /login ' - timeout_error: 'Login time-out: het duurde te lang tot je inlogde.' - -# Errors -error: - denied_command: '&cJe moet ingelogd zijn om dit commando te gebruiken!' - denied_chat: '&cJe moet ingelogd zijn om te kunnen chatten!' - unregistered_user: '&cDeze gebruikersnaam is niet geregistreerd!' - not_logged_in: '&cNiet ingelogd!' - no_permission: '&cJe hebt geen rechten om deze actie uit te voeren!' - unexpected_error: 'Er is een onverwachte fout opgetreden, neem contact op met een administrator!' - max_registration: 'Je hebt het maximum aantal registraties overschreden (%reg_count/%max_acc: %reg_names).' - logged_in: '&cJe bent al ingelogd!' - kick_for_vip: '&cEen VIP-gebruiker heeft ingelogd toen de server vol was!' - kick_unresolved_hostname: '&cEr heeft een fout plaatsgevonden: hostname van de speler kon niet gevonden worden!' - tempban_max_logins: '&cJe bent tijdelijk gebanned omdat het inloggen te vaak mislukt is.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot is aangezet! Wacht alsjeblieft enkele minuten voor je je met de server verbindt.' - auto_enabled: '[AuthMe] AntiBotMod automatisch aangezet vanwege te veel verbindingen!' - auto_disabled: '[AuthMe] AntiBotMod automatisch uitgezet na %m minuten!' - -# Unregister -unregister: - success: '&cSuccesvol afgemeld!' - command_usage: '&cGebruik: /unregister [wachtwoord]' - -# Other messages -misc: - account_not_activated: 'Je account is nog niet geactiveerd, controleer je mailbox!' - not_activated: '&cAccount niet geactiveerd, registreer en activeer het alstublieft voordat u het opnieuw probeert.' - password_changed: '&cWachtwoord succesvol aangepast!' - logout: '&2Je bent succesvol uitgelogd!' - reload: '&2De configuratie en database zijn succesvol herladen!' - usage_change_password: '&cGebruik: /changepassword ' - accounts_owned_self: 'Je bezit %count accounts:' - accounts_owned_other: 'De speler %name heeft %count accounts:' - -# Session messages -session: - valid_session: '&2Ingelogd wegens sessie-herverbinding.' - invalid_session: '&cJouw IP-adres is veranderd en je sessie is verlopen!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Een speler met hetzelfde IP-adres is al online!' - same_nick_online: '&4Er is al iemand met jouw gebruikersnaam online.' - name_length: '&4Jouw gebruikersnaam is te kort of te lang!' - characters_in_name: '&4Jouw gebruikersnaam bevat ongeldige tekens. Toegestane karakters zijn: %valid_chars' - kick_full_server: '&4De server is vol, probeer het later opnieuw!' - country_banned: '&4Jouw land is gebanned op deze server!' - not_owner_error: 'Jij bent niet de eigenaar van dit account. Kies alsjeblieft een andere naam!' - invalid_name_case: 'Verbind je alsjeblieft als %valid, niet als %invalid.' - quick_command: 'Je voerde te snel een commando uit! Verbind alsjeblieft opnieuw met de server en wacht langer voor het gebruiken van een commando.' - -# Email -email: - add_email_request: '&3Voeg jouw e-mailadres alsjeblieft toe met: /email add ' - usage_email_add: '&cGebruik: /email add ' - usage_email_change: '&cGebruik: /email change ' - new_email_invalid: '&cOngeldig nieuw e-mailadres, probeer het opnieuw!' - old_email_invalid: '&cOngeldig oud e-mailadres, probeer het opnieuw!' - invalid: '&cOngeldig E-mailadres, probeer het opnieuw!' - added: '&2Het e-mailadres is succesvol toegevoegd aan je account!' - add_not_allowed: '&cEen e-mailadres toevoegen is niet toegestaan' - request_confirmation: '&cVerifiëer je e-mailadres alsjeblieft!' - changed: '&2Het e-mailadres is succesvol veranderd!' - change_not_allowed: '&cEen e-mailadres wijzigen is niet toegestaan' - email_show: '&2Jouw huidige e-mailadres is: %email' - no_email_for_account: '&2Je hebt nog geen e-mailadres toegevoegd aan dit account.' - already_used: '&4Dit e-mailadres wordt al gebruikt' - incomplete_settings: 'Fout; er moeten nog enkele opties ingevuld worden om mails te kunnen sturen. Neem contact op met een administrator.' - send_failure: 'De e-mail kon niet verzonden worden. Neem contact op met een administrator.' - change_password_expired: 'Je kunt je wachtwoord niet meer veranderen met dit commando.' - email_cooldown_error: '&cEr is recent al een e-mail verzonden. Je moet %time wachten voordat je een nieuw bericht kunt versturen.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Wachtwoord vergeten? Gebruik alsjeblieft het commando: /email recovery ' - command_usage: '&cGebruik: /email recovery ' - email_sent: '&2Een herstel e-mail is verzonden! Check alsjeblieft je mailbox!' - code: - code_sent: 'Een herstelcode voor je wachtwoord is naar je mailbox gestuurd.' - incorrect: 'De herstelcode is niet correct! Je kunt het nog %count keer proberen.' - tries_exceeded: 'Je hebt het maximum aantal pogingen om een herstel code in te vullen bereikt. Gebruik "/email recovery [e-mail]" om een nieuwe code te krijgen' - correct: 'De herstelcode is correct!' - change_password: 'Gebruik alsjeblieft het commando /email setpassword om je wachtwoord direct te veranderen.' - -# Captcha -captcha: - usage_captcha: '&3Om in te loggen moet je een captcha-code oplossen, gebruik het commando: /captcha %captcha_code' - wrong_captcha: '&cVerkeerde captcha-code, typ alsjeblieft "/captcha %captcha_code" in de chat!' - valid_captcha: '&2De captcha-code is geldig!' - captcha_for_registration: 'Om je te registreren moet je eerst een captcha oplossen. Gebruik alsjeblieft het volgende commando: /captcha %captcha_code' - register_captcha_valid: 'Valide puzzel! Je mag je nu registreren met /register' - -# Verification code -verification: - code_required: '&3Dit commando is gevoelig en vereist een e-mail verificatie! Bekijk je inbox en volg de opgegeven instructies.' - command_usage: '&cGebruik: /verification ' - incorrect_code: '&cIncorrecte code, type alsjeblieft "/verification " in de chat met de code die je hebt ontvangen in je email' - success: '&2Je identiteit is vastgesteld! Je kan nu alle commandos uitvoeren tijdens deze sessie!' - already_verified: '&2Je kan momenteel alle gevoelige commandos al uitvoeren!' - code_expired: '&3Je code is verlopen! Voer een nieuw gevoelig commando uit om een nieuwe code te ontvangen!' - email_needed: '&3Om je identiteit vast te stellen moet je een e-mailadres verbinden aan je account!!' - -# Time units -time: - second: 'seconde' - seconds: 'seconden' - minute: 'minuut' - minutes: 'minuten' - hour: 'uur' - hours: 'uren' - day: 'dag' - days: 'dagen' - -# Two-factor authentication -two_factor: - code_created: '&2Je geheime code is %code. Je kunt hem scannen op %url' - confirmation_required: 'Verifieer alsjeblieft je code met /2fa confirm ' - code_required: 'Stuur alsjeblieft je twee-factor authenticatie code met /2fa code ' - already_enabled: 'Twee-factor authenticatie is al aangezet voor jouw account!' - enable_error_no_code: 'Geen 2fa-sleutel is voor jou gegenereerd. Of hij is verlopen. Voer alsjeblieft "/2fa add" uit' - enable_success: 'Je hebt successvol twee-factor authenticatie ingeschakelt voor jou account' - enable_error_wrong_code: 'Foutieve, of verlopen code. Voer alsjeblieft "/2fa add" uit.' - not_enabled_error: 'Twee-factor authenticatie is uitgeschakeld voor jou account. Voer "/2fa add" uit' - removed_success: 'Twee-factor authenticatie is met succes van jouw account verwijderd.' - invalid_code: 'Ongeldige code!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock automatisch inloggen gelukt!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aU zit vast in een portal tijdens het inloggen.' - fix_underground: '&aU zit vast onder de grond tijdens het inloggen.' - cannot_fix_underground: '&aU zit vast onder de grond tijdens het inloggen, maar we kunnen het niet repareren.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cU bent losgekoppeld vanwege een dubbele inlog.' diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml deleted file mode 100644 index e263df56..00000000 --- a/src/main/resources/messages/messages_pl.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&4Rejestracja jest wyłączona.' - name_taken: '&4Gracz już jest zarejestrowany.' - register_request: '&2Proszę się zarejestrować przy użyciu &6/register ' - command_usage: '&4Użycie: /register ' - reg_only: '&fTylko zarejestrowani użytkownicy mają do tego dostęp!' - success: '&aPomyślnie zarejestrowany!' - kicked_admin_registered: 'Administrator zarejestrował Ciebie, możesz się zalogować.' - -# Password errors on registration -password: - match_error: '&fHasło niepoprawne!' - name_in_password: '&cNie możesz używać nicku jako hasła, wybierz inne...' - unsafe_password: '&cTwoje hasło nie jest bezpieczne, wybierz inne...' - forbidden_characters: '&4W twoim haśle występują niedozwolone znaki, dozwolone znaki to: %valid_chars' - wrong_length: '&fTwoje hasło jest za krótkie lub za długie! Spróbuj ponownie...' - pwned_password: '&cTwoje wybrane hasło nie jest bezpieczne. Zostało już użyte %pwned_count razy! Proszę użyj silnego hasła...' - -# Login -login: - command_usage: '&cUżycie: /login hasło' - wrong_password: '&cNiepoprawne hasło.' - success: '&aHasło zaakceptowane!' - login_request: '&2Proszę się zalogować przy użyciu &6/login ' - timeout_error: '&cUpłynął limit czasu zalogowania' - -# Errors -error: - denied_command: '&cAby użyć tej komendy musisz się zalogować!' - denied_chat: '&cAby pisać na chacie musisz się zalogować!' - unregistered_user: '&fGracz nie jest zarejestrowany.' - not_logged_in: '&4Nie jesteś zalogowany!' - no_permission: '&4Nie posiadasz wymaganych uprawnień.' - unexpected_error: '&fWystąpił błąd, prosimy skontaktować się z administracją serwera.' - max_registration: '&cPrzekroczyłeś limit zarejestrowanych kont na serwerze &8(&e%reg_count/%max_acc %reg_names&8) &cdla twojego połączenia.' - logged_in: '&fJesteś już zalogowany!' - kick_for_vip: '&cGracz VIP dołączył do gry!' - kick_unresolved_hostname: '&cWystąpił błąd: nierozwiązana nazwa hosta gracza!' - tempban_max_logins: '&cZostałeś tymczasowo zbanowany za dużą liczbę nieudanych logowań!' - -# AntiBot -antibot: - kick_antibot: '&cAntyBot został włączony, musisz poczekać minutę przed dołączeniem do serwera.' - auto_enabled: '&4[AntiBot] &aAntyBot włączony z powodu dużej liczby połączeń!' - auto_disabled: '&2[AntiBot] &aAntyBot zostanie wyłączony za &7%m &aminut!' - -# Unregister -unregister: - success: '&4Pomyślnie wyrejestrowany!' - command_usage: '&cUżycie: /unregister hasło' - -# Other messages -misc: - account_not_activated: '&fTwoje konto nie zostało aktywowane! Sprawdź maila.' - not_activated: '&cKonto nieaktywowane, proszę zarejestruj się i aktywuj konto przed ponowną próbą.' - password_changed: '&fHasło zostało zmienione!' - logout: '&cPomyślnie wylogowany' - reload: '&fKonfiguracja bazy danych została przeładowana.' - usage_change_password: '&fUżycie: /changepassword ' - accounts_owned_self: '&7Posiadasz %count kont:' - accounts_owned_other: '&7Gracz %name posiada %count kont:' - -# Session messages -session: - valid_session: '&aZalogowano automatycznie z powodu sesji logowania.' - invalid_session: '&fSesja logowania zakończona!' - -# Error messages when joining -on_join_validation: - same_ip_online: '&cGracz z takim samym adresem ip jest aktualnie w grze!' - same_nick_online: '&fTen nick już gra na serwerze!' - name_length: '&cTwoje konto ma za długa bądź za krotką nazwę.' - characters_in_name: '&cTwoje konto ma w nazwie niedozwolone znaki. Dozwolone znaki: %valid_chars' - kick_full_server: '&cSerwer jest teraz zapełniony, przepraszamy!' - country_banned: '&4Ten kraj jest zbanowany na tym serwerze' - not_owner_error: '&cNie jesteś właścicielem tego konta, wybierz inny nick!' - invalid_name_case: '&cPowinieneś dołączyć do serwera z nicku %valid, a nie %invalid.' - quick_command: '&cUżyłeś komendy zbyt szybko! Ponownie dołącz do serwera i poczekaj chwilę, zanim użyjesz dowolnej komendy.' - -# Email -email: - add_email_request: '&cProszę dodać swój e-mail: /email add ' - usage_email_add: '&fWpisz: /email add ' - usage_email_change: '&fWpisz: /email change ' - new_email_invalid: '[AuthMe] Nowy e-mail niepoprawny!' - old_email_invalid: '[AuthMe] Stary e-mail niepoprawny!' - invalid: '[AuthMe] Nieprawidłowy adres e-mail.' - added: '[AuthMe] E-mail został dodany do Twojego konta!' - add_not_allowed: '&cMożliwość dodania adresu e-mail jest wyłączona.' - request_confirmation: '[AuthMe] Potwierdź swój adres e-mail!' - changed: '[AuthMe] E-mail został zmieniony!' - change_not_allowed: '&cMożliwość zmiany adresu e-mail jest wyłączona.' - email_show: '&2Twój aktualny adres e-mail to: &f%email' - no_email_for_account: '&2Nie posiadasz adresu e-mail przypisanego do tego konta.' - already_used: '&4Ten adres e-mail jest aktualnie używany!' - incomplete_settings: 'Błąd: Nie wszystkie opcje odpowiedzialne za wysyłanie e-maili zostały skonfigurowane. Skontaktuj się z administracją.' - send_failure: 'Nie można wysłać e-maila. Skontaktuj się z administracją.' - change_password_expired: 'Nie zmienisz już hasła przy użyciu tej komendy.' - email_cooldown_error: '&cE-mail został wysłany, musisz poczekać %time przed wysłaniem następnego.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cZapomniałeś hasła? Proszę użyj komendy /email recovery ' - command_usage: '&fWpisz: /email recovery ' - email_sent: '[AuthMe] E-mail z odzyskaniem wysłany!' - code: - code_sent: 'Kod odzyskiwania hasła został wysłany na adres e-mail przypisany do konta.' - incorrect: '&cKod odzyskiwania hasła jest błędny! &4Pozostałe próby: %count.' - tries_exceeded: 'Osiągnięto limit prób wpisania kodu odzyskiwania. Wpisz /email recovery [e-mail] aby wygenerować nowy kod.' - correct: '&aKod odzyskiwania został wpisany pomyślnie!' - change_password: 'Wpisz komendę /email setpassword aby zmienić hasło do konta.' - -# Captcha -captcha: - usage_captcha: '&cWpisz: /captcha %captcha_code' - wrong_captcha: '&cZły kod, proszę wpisać: /captcha %captcha_code' - valid_captcha: '&cTwój kod jest nieprawidłowy!' - captcha_for_registration: '&cAby się zarejestrować, musisz przepisać kod captacha. Użyj komendy: /captcha %captcha_code' - register_captcha_valid: '&2Prawidłowy kod captacha! Teraz możesz się zarejestrować komendą /register' - -# Verification code -verification: - code_required: '&3Ta komenda wymaga weryfikacji przez e-mail! Sprawdź swoją skrzynkę odbiorczą i postępuj zgodnie z instrukcjami w wiadomości.' - command_usage: '&cUżycie: /verification ' - incorrect_code: '&cNieprawidłowy kod z e-maila, wpisz komende "/verification ". W miejscu wpisz swój kod z emaila.' - success: '&2Twoja tożsamość została zweryfikowana! Możesz teraz wykonywać wszystkie komendy w bieżącej sesji!' - already_verified: '&2Możesz już wykonać każdą komende w bieżącej sesji!' - code_expired: '&3Twój kod wygasł! Wykonaj ponownie komende, aby uzyskać nowy kod!' - email_needed: '&3Aby zweryfikować swoją tożsamość, musisz połączyć adres e-mail z kontem!' - -# Time units -time: - second: 'sekundy' - seconds: 'sekund' - minute: 'minuty' - minutes: 'minut' - hour: 'godziny' - hours: 'godzin' - day: 'dzień' - days: 'dni' - -# Two-factor authentication -two_factor: - code_created: '&2Twój sekretny kod to %code. Możesz zeskanować go tutaj: %url' - confirmation_required: 'Musisz potwierdzić swój kod komendą /2fa confirm ' - code_required: 'Wpisz swój kod weryfikacji dwuetapowej przy pomocy komendy /2fa code ' - already_enabled: '&aWeryfikacja dwuetapowa jest już włączona dla Twojego konta.' - enable_error_no_code: '&cKod weryfikacji dwuetapowej nie został dla Ciebie wygenerowany lub wygasł. Wpisz komende /2fa add' - enable_success: '&aWeryfikacja dwuetapowa została włączona dla Twojego konta.' - enable_error_wrong_code: '&cWpisany kod jest nieprawidłowy lub wygasły. Wpisz ponownie /2fa add' - not_enabled_error: 'Weryfikacja dwuetapowa nie jest włączona dla twojego konta. Wpisz komende /2fa add' - removed_success: '&aPomyślnie usunięto weryfikacje dwuetapową z Twojego konta.' - invalid_code: '&cWpisany kod jest nieprawidłowy, spróbuj jeszcze raz.' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aAutomatyczne logowanie na Bedrocku udane!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aUtknąłeś w portalu podczas logowania.' - fix_underground: '&aUtknąłeś pod ziemią podczas logowania.' - cannot_fix_underground: '&aUtknąłeś pod ziemią podczas logowania, ale nie możemy tego naprawić.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cZostałeś rozłączony z powodu podwójnego logowania.' diff --git a/src/main/resources/messages/messages_pt.yml b/src/main/resources/messages/messages_pt.yml deleted file mode 100644 index d8352e51..00000000 --- a/src/main/resources/messages/messages_pt.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegisto de novos utilizadores desactivado' - name_taken: '&cUtilizador já registado' - register_request: '&cPor favor registe-se com "/register "' - command_usage: '&cUse: /register ' - reg_only: '&fApenas jogadores registados podem entrar no servidor! Visite https://example.com para se registar' - success: '&cRegistado com sucesso!' - kicked_admin_registered: 'Um administrador registou-te, por favor entre novamente' - -# Password errors on registration -password: - match_error: '&fAs passwords não coincidem' - name_in_password: '&cNão pode o usar seu nome como senha, por favor, escolha outra ...' - unsafe_password: '&cA senha escolhida não é segura, por favor, escolha outra ...' - forbidden_characters: '&4Sua senha contém caracteres ilegais. Caracteres permitidos: %valid_chars' - wrong_length: '&fPassword demasiado curta ou longa! Por favor escolhe outra outra!' - pwned_password: '&cA senha escolhida não é segura. Ela foi usada %pwned_count vezes! Por favor, use uma senha forte...' - -# Login -login: - command_usage: '&cUse: /login ' - wrong_password: '&cPassword errada!' - success: '&bAutenticado com sucesso!' - login_request: '&cIdentifique-se com "/login "' - timeout_error: '&fExcedeu o tempo para autenticação' - -# Errors -error: - denied_command: '&cPara utilizar este comando é necessário estar logado!' - denied_chat: '&cPara usar o chat deve estar logado!' - unregistered_user: '&cUsername não registado' - not_logged_in: '&cNão autenticado!' - no_permission: '&cSem Permissões' - unexpected_error: '&fOcorreu um erro; Por favor contacte um administrador' - max_registration: '&cAtingiu o numero máximo de %reg_count contas registas, maximo de contas %max_acc' - logged_in: '&cJá se encontra autenticado!' - kick_for_vip: '&cUm jogador VIP entrou no servidor cheio!' - kick_unresolved_hostname: '&cOcorreu um erro: nome do servidor do jogador não resolvido!' - tempban_max_logins: '&cVocê foi temporariamente banido por falhar muitas vezes o login.' - -# AntiBot -antibot: - kick_antibot: 'Modo de protecção anti-Bot está habilitado! Tem que espere alguns minutos antes de entrar no servidor.' - auto_enabled: '[AuthMe] AntiBotMod activado automaticamente devido a um aumento anormal de tentativas de ligação!' - auto_disabled: '[AuthMe] AntiBotMod desactivado automaticamente após %m minutos, esperamos que a invasão tenha parado' - -# Unregister -unregister: - success: '&cRegisto eliminado com sucesso!' - command_usage: '&cUse: /unregister ' - -# Other messages -misc: - account_not_activated: '&fA sua conta não foi ainda activada, verifique o seu email onde irá receber indicações para activação de conta. ' - not_activated: '&cConta não ativada, por favor, registre-se e ative antes de tentar novamente.' - password_changed: '&cPassword alterada!' - logout: '&cSaida com sucesso' - reload: '&fConfiguração e base de dados foram recarregadas' - usage_change_password: '&fUse: /changepassword ' - accounts_owned_self: 'Você possui %count contas:' - accounts_owned_other: 'O jogador %name possui %count contas:' - -# Session messages -session: - valid_session: '&cSessão válida' - invalid_session: '&fDados de sessão não correspondem. Por favor aguarde o fim da sessão' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Um jogador com o mesmo IP já está em jogo!' - same_nick_online: '&fO mesmo nickname já se encontra a jogar no servidor' - name_length: '&cO seu nick é demasiado curto ou muito longo.' - characters_in_name: '&cO seu nickname contém caracteres não permitidos. Permitido: %valid_chars' - kick_full_server: '&cO servidor está actualmente cheio, lamentamos!' - country_banned: 'O seu país está banido deste servidor' - not_owner_error: 'Não é o proprietário da conta. Por favor, escolha outro nome!' - invalid_name_case: 'Deve se juntar usando nome de usuário %valid, não %invalid.' - quick_command: 'Você usou o comando demasiado rapido por favor re-entre no servidor e aguarde antes de digitar qualquer comando.' - -# Email -email: - add_email_request: '&cPor favor adicione o seu email com : /email add ' - usage_email_add: '&fUse: /email add ' - usage_email_change: '&fUse: /email change ' - new_email_invalid: 'Novo email inválido!' - old_email_invalid: 'Email antigo inválido!' - invalid: 'Email inválido!' - added: 'Email adicionado com sucesso!' - add_not_allowed: '&cAdicionar e-mail não é permitido' - request_confirmation: 'Confirme o seu email!' - changed: 'Email alterado com sucesso!' - change_not_allowed: '&cAlterar e-mail não é permitido' - email_show: '&2O seu endereço de email atual é &f%email' - no_email_for_account: '&2Você atualmente não tem um endereço de email associado a essa conta.' - already_used: '&4O endereço de e-mail já está sendo usado' - incomplete_settings: 'Erro: nem todas as definições necessarias para enviar email foram preenchidas. Por favor contate um administrador.' - send_failure: 'Não foi possivel enviar o email. Por favor contate um administrador.' - change_password_expired: 'Você não pode mais alterar a sua password usando este comando.' - email_cooldown_error: '&cUm email já foi enviado recentemente.Por favor, espere %time antes de enviar novamente' - -# Password recovery by email -recovery: - forgot_password_hint: '&cPerdeu a sua password? Para a recuperar escreva /email recovery ' - command_usage: '&fUse: /email recovery ' - email_sent: 'Nova palavra-passe enviada para o seu email!' - code: - code_sent: 'O codigo para redefinir a senha foi enviado para o seu e-mail.' - incorrect: 'O codigo de recuperação está incorreto! Use "/email recovery [email]" para gerar um novo' - tries_exceeded: 'Você excedeu o numero maximo de tentativas para introduzir o codigo de recuperação. Use "/email recovery [email]" para gerar um novo.' - correct: 'O codigo de recuperação foi introduzido corretamente!' - change_password: 'Por favor use o comando /email setpassword para mudar a password imediatamente.' - -# Captcha -captcha: - usage_captcha: '&cPrecisa digitar um captcha, escreva: /captcha %captcha_code' - wrong_captcha: '&cCaptcha errado, por favor escreva: /captcha %captcha_code' - valid_captcha: '&cO seu captcha é válido!' - captcha_for_registration: 'Para se registar tem de resolver o captcha primeiro, por favor use: /captcha %captcha_code' - register_captcha_valid: '&2Captcha Valido! Agora você pode te registar com /register' - -# Verification code -verification: - code_required: '&3Este codigo é sensivel e requer uma verificação por e-mail! Verifique na sua caixa de entrada e siga as instruções do e-mail.' - command_usage: '&cUso: /verification ' - incorrect_code: '&cCodigo incorreto, por favor digite "/verification " no chat, utilizando o codigo que recebeu no e-mail.' - success: '&2Sua identidade foi verificada! Agora você pode executar todos os comandos nesta sessão!' - already_verified: '&2Você já pode digitar todos os comandos sensiveis nesta sessão!' - code_expired: '&3Seu codigo expirou! Execute outro comando sensivel para obter um novo codigo!' - email_needed: '&3Para confirmar a sua identidade necessita de associar um endereço de e-mail!!' - -# Time units -time: - second: 'segundo' - seconds: 'segundos' - minute: 'minuto' - minutes: 'minutos' - hour: 'hora' - hours: 'horas' - day: 'dia' - days: 'dias' - -# Two-factor authentication -two_factor: - code_created: '&2O seu código secreto é o %code. Você pode verificá-lo a partir daqui %url' - confirmation_required: 'Por favor confirme seu codigo de 2 etapas com /2fa confirm ' - code_required: 'Por favor submita seu codigo de duas etapas com /2fa code ' - already_enabled: 'Autenticação de duas etapas já se encontra habilitada na sua conta!' - enable_error_no_code: 'Nenhuma chave 2fa foi gerada por você ou expirou. Por favor digite /2fa add' - enable_success: 'Autenticação de duas etapas habilitada com sucesso na sua conta' - enable_error_wrong_code: 'Codigo errado ou o codigo expirou. Por favor digite /2fa add' - not_enabled_error: 'Autenticação de duas etapas não está habilitada na sua conta. Digite /2fa add' - removed_success: 'Autenticação de duas etapas removida com sucesso da sua conta' - invalid_code: 'Codigo invalido!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aLogin automático no Bedrock bem-sucedido!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aVocê está preso no portal durante o login.' - fix_underground: '&aVocê está preso no subsolo durante o login.' - cannot_fix_underground: '&aVocê está preso no subsolo durante o login, mas não podemos consertar.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cVocê foi desconectado devido a um login duplicado.' diff --git a/src/main/resources/messages/messages_ro.yml b/src/main/resources/messages/messages_ro.yml deleted file mode 100644 index dc8d3b1b..00000000 --- a/src/main/resources/messages/messages_ro.yml +++ /dev/null @@ -1,172 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cInregistrarea in joc nu este activata!' - name_taken: '&cCineva este inregistrat cu acest nume!' - register_request: '&3Te rugam sa te inregistrezi folosind comanda "/register "' - command_usage: '&cFoloseste comanda: /register ' - reg_only: '&4Doar jucatori inregistrati pot intra pe server! Te rugam foloseste https://example.com pentru a te inregistra!' - success: '&2Te-ai inregistrat cu succes!' - kicked_admin_registered: 'Un administrator tocmai te-a inregistrat, te rog autentifica-te din nou.' - -# Password errors on registration -password: - match_error: '&cParolele nu corespund, verifica-le din nou!' - name_in_password: '&c&cNu poti folosi numele ca si parola. Te rugam sa folosesti alta parola...' - unsafe_password: '&cParola aleasa nu este sigura. Te rugam sa folosesti alta parola...' - forbidden_characters: '&4Parola ta contine caractere nepermise. Caractere permise: %valid_chars' - wrong_length: '&cParola ta este prea scurta pentru a te inregistra! Te rugam incearca alta parola!' - pwned_password: '&cParola aleasă nu este sigură. A fost folosită de %pwned_count ori! Vă rugăm să utilizați o parolă puternică...' - -# Login -login: - command_usage: '&cFoloseste comanda "/login " pentru a te autentifica.' - wrong_password: '&cParola gresita!' - success: '&2Te-ai autentificat cu succes!' - login_request: '&cTe rugam sa te autentifici folosind comanda: /login ' - timeout_error: '&4A expirat timpul de autentificare si ai fost dat afara de server, te rugam incearca din nou!' - -# Errors -error: - denied_command: '&cPentru a utiliza aceasta comanda trebuie sa fi autentificat!' - denied_chat: '&cPentru a utiliza chat-ul trebuie sa fi autentificat!' - unregistered_user: '&cAcest jucator nu este inregistrat!' - not_logged_in: '&cNu esti autentificat!' - no_permission: '&4Nu ai permisiunea de a efectua aceasta actiune!' - unexpected_error: '&4A aparut o eroare, te rugam contacteaza un administrator!' - max_registration: '&cAi depasit numarul maxim de inregistrari (%reg_count /%max_acc %reg_names) pentru conexiunea dvs.!' - logged_in: '&cEsti deja autentificat!' - kick_for_vip: '&3Un VIP a intrat pe server cand era plin!' - kick_unresolved_hostname: '&cA aparut o eroare: nume gazda nerezolvat!' - tempban_max_logins: '&cAi fost banat temporar deoarece ai esuat sa te autentifici de prea multe ori.' - -# AntiBot -antibot: - kick_antibot: 'Protectia AntiBot este activata! Trebuie sa astepti cateva minute pentru a intra pe server.' - auto_enabled: '&4[Protectie AntiBot] AntiBot-ul a fost activat din cauza numarului mare de conexiuni!' - auto_disabled: '&2[Protectie AntiBot] AntiBot-ul a fost dezactivat dupa %m minute!' - -unregister: - success: '&cTi-ai sters contul cu succes!' - command_usage: '&cFoloseste comanda: /unregister ' - -# Other messages -misc: - account_not_activated: '&cContul tau nu este activat, te rugam verifica-ti email-ul!' - not_activated: '&cContul nu este activat, vă rugăm să vă înregistrați și să îl activați înainte de a încerca din nou.' - password_changed: '&2Parola a fost schimbata cu succes!' - logout: '&2Te-ai deconectat cu succes!' - reload: '&2Configuratiile si baza de date s-au reincarcat corect!' - usage_change_password: '&cFoloseste comanda: /changepassword ' - accounts_owned_self: 'Detii %count conturi:' - accounts_owned_other: 'Jucatorul %name are %count conturi:' - -# Session messages -session: - valid_session: '&2Conectat datorita reconectarii sesiunii.' - invalid_session: '&cIP-ul tau a fost schimbat si sesiunea ta a expirat!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Un jucator cu acelasi IP este deja in joc!' - same_nick_online: '&4Acelasi nume apartine unui jucator care e deja pe server!' - name_length: '&4Numele tau este fie prea scurt, fie prea lung!' - characters_in_name: '&4Numele tau contine caractere ilegale. Caractere permise: %valid_chars' - kick_full_server: '&4Server-ul este plin, incearca mai tarziu!' - country_banned: '&4Tara ta este interzisa pe acest server!' - not_owner_error: 'Tu nu esti detinatorul acestui cont. Te rugam alege alt nume!' - invalid_name_case: 'Ar trebui sa intri cu numele %valid, nu %invalid' - quick_command: 'Ai folosit o comanda prea repede! Te rugam, intra din nou pe server si astepta mai mult inainte de a utiliza orice comanda.' - -# Email -email: - add_email_request: '&3Te rugam adaugati email-ul la contul tau folosind comanda "/email add "' - usage_email_add: '&cFoloseste comanda: /email add ' - usage_email_change: '&cFoloseste comanda: /email change ' - new_email_invalid: '&cNoul email este nevalid, incearca din nou!' - old_email_invalid: '&cEmail-ul vechi este nevalid, incearca din nou!' - invalid: '&cEmail-ul este nevalid, incearca din nou!' - added: '&2Email-ul a fost adaugat cu succes la contul tau!' - add_not_allowed: '&cAdaugarea email-ului nu a fost permisa.' - request_confirmation: '&cTe rugam sa confirmi adresa ta de email!' - changed: '&2Email-ul a fost schimbat cu succes!' - change_not_allowed: '&cModificarea email-ului nu a fost permisa.' - email_show: '&2Adresa ta curenta de email este: &f%email' - no_email_for_account: '&2Nu ai nici o adresa de email asociata cu acest cont.' - already_used: '&4Email-ul acesta este deja folosit de altcineva' - incomplete_settings: 'Eroare: Nu indeplinesti conditiile trimiterii unui email! Te rugam contacteaza un administrator.' - send_failure: 'Email-ul nu a putut fi trimis. Ta rugam contactatezi un administrator.' - change_password_expired: 'Nu mai iti poti schimba parola folosind aceasta comanda.' - email_cooldown_error: '&cAi primit deja un mail pentru schimbarea parolei. Trebuie sa astepti %time inainte de a trimite unul nou.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Ti-ai uitat parola? Te rugam foloseste comanda "/email recovery "' - command_usage: '&cFoloseste comanda: /email recovery ' - email_sent: '&2Email-ul de recuperarea a fost trimis cu succes! Te rugam sa verifici casuta de email!' - code: - code_sent: 'Un cod de recuperare a parolei a fost trimis catre email-ul tau.' - incorrect: 'Codul de recuperare nu este corect! Mai ai %count incercari ramase.' - tries_exceeded: 'Ai atins numarul maxim de incercari pentru introducerea codului de recuperare. Foloseste "/email recovery [email]" pentru a genera unul nou.' - correct: 'Cod de recuperare corect!' - change_password: 'Foloseste imediat comanda /email setpassword pentru a-ti schimba parola.' - -# Captcha -captcha: - usage_captcha: '&3Pentru a te autentifica, trebuie sa rezolvi un cod captcha, foloseste comanda: /captcha %captcha_code' - wrong_captcha: '&cCodul de verificare este gresit, te rugam foloseste comanda: /captcha %captcha_code' - valid_captcha: '&2Codul de verificare a fost scris corect!' - captcha_for_registration: 'Pentru a te inregistra, trebuie sa rezolvi mai intai un captcha, foloseste comanda: /captcha %captcha_code' - register_captcha_valid: '&2Captcha valid! Poti sa te inregistrezi acum cu /register' - -# Verification code -verification: - code_required: '&3Aceasta comanda este sensibila si necesita o verificare prin email! Verificati adresa de email si urmati instructiunile de pe email.' - command_usage: '&cFoloseste: /verification ' - incorrect_code: '&cCod incorect, te rugam sa foloseste "/verification " in chat, folosind codul pe care l-ai primit prin email' - success: '&2Identitatea ta a fost verificata! Acum poti executa toate comenzile in sesiunea curenta!' - already_verified: '&2Poti deja sa executi fiecare comanda sensibila in cadrul sesiunii curente!' - code_expired: '&3Codul tau a expirat! Executa o alta comanda sensibila pentru a obtine un cod nou!' - email_needed: '&3Pentru ati verifica identitatea, trebuie sa conectezi o adresa de email cu contul tau!!' - -# Time units -time: - second: 'secunda' - seconds: 'secunde' - minute: 'minut' - minutes: 'minute' - hour: 'ora' - hours: 'ore' - day: 'zi' - days: 'zile' - -# Two-factor authentication -two_factor: - code_created: '&2Codul tau secret este %code. Il poti scana de aici %url' - confirmation_required: 'Te rugam sa confirmi codul tau cu /2fa confirm ' - code_required: 'Te rugam sa trimiti codul tau de autentificare in doi pasi cu /2fa code ' - already_enabled: 'Autentificarea in doi pasi este deja activata pentru contul tau!' - enable_error_no_code: 'Nicio cheie 2fa nu a fost generata pentru tine sau a expirat. te rugam sa folosesti /2fa add' - enable_success: 'Activarea cu succes a autentificarii in doi pasi pentru contul tau' - enable_error_wrong_code: 'Cod gresit sau codul a expirat. Te rugam sa folosesti /2fa add' - not_enabled_error: 'Autentificarea in doi pasi nu este activata pentru contul tau. foloseste /2fa add' - removed_success: 'Eliminare cu succes a autentificarii in doi pasi de pe cont' - invalid_code: 'Cod invalid!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aAutentificare automată Bedrock reușită!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aSunteți blocat în portal în timpul autentificării.' - fix_underground: '&aSunteți blocat sub pământ în timpul autentificării.' - cannot_fix_underground: '&aSunteți blocat sub pământ în timpul autentificării, dar nu putem remedia.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cAți fost deconectat din cauza unei autentificări duble.' diff --git a/src/main/resources/messages/messages_ru.yml b/src/main/resources/messages/messages_ru.yml deleted file mode 100644 index 42ac6320..00000000 --- a/src/main/resources/messages/messages_ru.yml +++ /dev/null @@ -1,172 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cРегистрация отключена.' - name_taken: '&cИгрок с таким никнеймом уже зарегистрирован.' - register_request: '&3Регистрация: /reg <пароль> <повтор пароля>' - command_usage: '&cИспользование: /reg <пароль> <повтор пароля>' - reg_only: '&4Вход только для зарегистрированных! Посетите https://сайт_сервера.ru для регистрации.' - success: '&2Вы успешно зарегистрировались!' - kicked_admin_registered: 'Администратор зарегистрировал вас. Авторизуйтесь снова.' - -# Password errors on registration -password: - match_error: '&cПароли не совпадают.' - name_in_password: '&cНельзя использовать свой никнейм в качестве пароля.' - unsafe_password: '&cТакой пароль небезопасен.' - forbidden_characters: '&4Пароль содержит запрещённые символы. Разрешённые: %valid_chars' - wrong_length: '&cПароль слишком длинный/короткий.' - pwned_password: '&cВыбранный вами пароль небезопасен. Он уже был использован %pwned_count раз! Пожалуйста, используйте надежный пароль...' - -# Login -login: - command_usage: '&cИспользование: /login <пароль>' - wrong_password: '&cНеправильный пароль!' - success: '&2Вы успешно вошли!' - login_request: '&3Авторизация: /login <Пароль>' - timeout_error: '&4Время авторизации истекло.' - -# Errors -error: - denied_command: '&cНеобходимо авторизоваться для использования этой команды!' - denied_chat: '&cНеобходимо авторизоваться, чтобы писать в чат!' - unregistered_user: '&cИгрок с таким именем не зарегистрирован.' - not_logged_in: '&cВы ещё не вошли!' - no_permission: '&4Недостаточно прав.' - unexpected_error: '&cПроизошла ошибка. Свяжитесь с администратором.' - max_registration: '&cПревышено максимальное количество регистраций на сервере! (%reg_count/%max_acc %reg_names)' - logged_in: '&cВы уже авторизированы!' - kick_for_vip: '&3VIP-игрок зашёл на переполненный сервер.' - kick_unresolved_hostname: '&cПроизошла ошибка: неразрешенное имя узла игрока!' - tempban_max_logins: '&cВы временно заблокированы из-за большого количества неудачных попыток авторизоваться.' - -# AntiBot -antibot: - kick_antibot: 'Сработала защита против ботов! Необходимо подождать перед следующим входом на сервер.' - auto_enabled: '&4[AuthMe] AntiBot-режим включился из-за большого количества входов!' - auto_disabled: '&2[AuthMe] AntiBot-режим отключился спустя %m мин.' - -unregister: - success: '&cУчётная запись успешно удалена!' - command_usage: '&cИспользование: /unregister <пароль>' - -# Other messages -misc: - account_not_activated: '&cВаша уч. запись ещё не активирована. Проверьте электронную почту!' - not_activated: '&cАккаунт не активирован, пожалуйста, зарегистрируйтесь и активируйте его перед повторной попыткой.' - password_changed: '&2Ваш пароль изменён!' - logout: '&2Успешно вышли из системы!' - reload: '&6Конфигурация и база данных перезагружены.' - usage_change_password: '&cИспользование: /changepassword <пароль> <новый пароль>' - accounts_owned_self: 'У вас %count уч. записей:' - accounts_owned_other: 'У игрока %name %count уч. записей:' - -# Session messages -session: - valid_session: '&2Вы автоматически авторизовались!' - invalid_session: '&cСессия некорректна. Дождитесь, пока она закончится.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Игрок с данным IP-адресом уже играет на сервере!' - same_nick_online: '&4Игрок с данным никнеймом уже играет на сервере!' - name_length: '&4Ваш никнейм слишком длинный/короткий.' - characters_in_name: '&4Ваш никнейм содержит запрещённые символы. Разрешённые: %valid_chars' - kick_full_server: '&4Сервер полон. Попробуйте зайти позже!' - country_banned: '&4Вход с IP-адресов вашей страны запрещён на этом сервере.' - not_owner_error: 'Вы не являетесь владельцем данной уч. записи. Выберите себе другой никнейм!' - invalid_name_case: 'Неверный никнейм! Зайдите под никнеймом %valid, а не %invalid.' - quick_command: 'Вы вводили команды слишком часто! Пожалуйста, переподключитесь и вводите команды медленнее.' - -# Email -email: - add_email_request: '&3Добавьте электронную почту: /email add <эл. почта> <повтор эл. почты>' - usage_email_add: '&cИспользование: /email add <эл. почта> <повтор эл. почты>' - usage_email_change: '&cИспользование: /email change <эл. почта> <новая эл. почта>' - new_email_invalid: '&cНедействительная новая электронная почта!' - old_email_invalid: '&cНедействительная старая электронная почта!' - invalid: '&cНедействительный адрес электронной почты!' - added: '&2Электронная почта успешно добавлена!' - add_not_allowed: '&cДобавление электронной почты не было разрешено.' - request_confirmation: '&cПодтвердите свою электронную почту!' - changed: '&2Адрес электронной почты изменён!' - change_not_allowed: '&cИзменение электронной почты не было разрешено.' - email_show: '&2Текущий адрес электронной почты — &f%email' - no_email_for_account: '&2К вашей уч. записи не привязана электронная почта.' - already_used: '&4Эта электронная почта уже используется.' - incomplete_settings: 'Ошибка: не все необходимые параметры установлены для отправки электронной почты. Свяжитесь с администратором.' - send_failure: 'Письмо не может быть отправлено. Свяжитесь в администратором.' - change_password_expired: 'Больше нельзя сменить свой пароль, используя эту команду.' - email_cooldown_error: '&cПисьмо было отправлено недавно. Подождите %time, прежде чем отправить новое.' - -# Password recovery by email -recovery: - forgot_password_hint: '&Забыли пароль? Используйте «/email recovery <эл. почта>».' - command_usage: '&cИспользование: /email recovery <эл. почта>' - email_sent: '&2Письмо с инструкциями для восстановления было отправлено на вашу электронную почту!' - code: - code_sent: 'Код восстановления для сброса пароля был отправлен на электронную почту.' - incorrect: 'Неверный код восстановления! Попыток осталось: %count.' - tries_exceeded: 'Вы слишком много раз неверно ввели код восстановления. Используйте «/email recovery [эл. почта]», чтобы получить новый код.' - correct: 'Код восстановления введён верно!' - change_password: 'Используйте «/email setpassword <новый пароль>», чтобы сменить свой пароль.' - -# Captcha -captcha: - usage_captcha: '&3Необходимо ввести текст с каптчи. Используйте «/captcha %captcha_code»' - wrong_captcha: '&cНеверно! Используйте «/captcha %captcha_code».' - valid_captcha: '&2Вы успешно решили каптчу!' - captcha_for_registration: 'Чтобы зарегистрироваться, решите каптчу используя команду: «/captcha %captcha_code»' - register_captcha_valid: '&2Вы успешно решили каптчу! Теперь вы можете зарегистрироваться командой «/register»' - -# Verification code -verification: - code_required: '&3Эта команда чувствительна и требует подтверждения электронной почты! Проверьте свою почту и следуйте инструкциям в письме.' - command_usage: '&cИспользование: /verification <код>' - incorrect_code: '&cНеверный код, используйте «/verification <код>», подставив код из полученного письма.' - success: '&2Ваша личность подтверждена! Теперь можно выполнять все чувствительные команды в текущем сеансе!' - already_verified: '&2Вы уже можете выполнять все чувствительные команды в текущем сеансе!' - code_expired: '&3Срок действия кода истёк! Выполните чувствительную команду, чтобы получить новый код!' - email_needed: '&3Чтобы подтвердить вашу личность, необходимо привязать электронную почту к учётной записи!!' - -# Time units -time: - second: 'с.' - seconds: 'с.' - minute: 'мин.' - minutes: 'мин.' - hour: 'ч.' - hours: 'ч.' - day: 'дн.' - days: 'дн.' - -# Two-factor authentication -two_factor: - code_created: '&2Ваш секретный код — %code. Просканируйте его здесь: %url' - confirmation_required: 'Пожалуйста, подтвердите ваш код с помощью /2fa confirm <код>' - code_required: 'Пожалуйста, введите ваш код двухфакторной аутентификации используя команду /2fa code <код>' - already_enabled: 'Двухфакторная аутентификация уже активирована для вашего аккаунта!' - enable_error_no_code: 'Код двухфакторной аутентификации не был сгенерирован или истек. Пожалуйста, введите /2fa add' - enable_success: 'Двухфакторная аутентификация для вашего аккаунта успешно подключена' - enable_error_wrong_code: 'Срок действия кода истек или код неверный. Введите /2fa add' - not_enabled_error: 'Двухфакторная аутентификация не включена для вашего аккаунта. Введите /2fa add' - removed_success: 'Двухфакторная аутентификация успешно удалена с вашего аккаунта!' - invalid_code: 'Неверный код!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aВы автоматически авторизовались потому что вы играете с Bedrock!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aВы застряли в портале во время авторизации.' - fix_underground: '&aВы застряли под землей во время авторизации.' - cannot_fix_underground: '&aВы застряли под землей во время авторизации, но мы не можем это исправить.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cВы были отключены из-за двойного входа.' diff --git a/src/main/resources/messages/messages_si.yml b/src/main/resources/messages/messages_si.yml deleted file mode 100644 index d046e480..00000000 --- a/src/main/resources/messages/messages_si.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegistracija v igri je onemogočena!' - name_taken: '&cTo uporabniško ime ste ze registrirali!' - register_request: '&3Registrirajte se z ukazom "/register "' - command_usage: '&cUporaba: /register ' - reg_only: '&4Samo registrirani uporabniki se lahko povezejo! Obiscite https://example.com , da se registrirate!' - success: '&2Uspešno registriran!' - kicked_admin_registered: 'Administrator vas je registriral; prosimo, da se prijavite.' - -# Password errors on registration -password: - match_error: '&cGesli se ne ujemata, ponovno ju preverite!' - name_in_password: '&cSvoje uporabniško ime ne morete uporabiti kot geslo, izberite drugo...' - unsafe_password: '&cIzbrano geslo ni varno, izberite drugo...' - forbidden_characters: '&4Vaše geslo vsebuje nedovoljene znake. Dovoljeni znaki: %valid_chars' - wrong_length: '&cVaše geslo je prekratko ali predolgo! Poskusite z drugim!' - pwned_password: '&cIzbrano geslo ni varno. Uporabljeno je bilo že %pwned_count krat! Prosimo, uporabite močno geslo...' - -# Login -login: - command_usage: '&cUporaba: /login ' - wrong_password: '&cNapačno geslo!' - success: '&2Uspešna prijava!' - login_request: '&cPrijavi se z ukazom "/login "' - timeout_error: '&4Časovna omejitev prijave prekoračena, vrzeni ste bili s strežnika, poskusite ponovno!' - -# Errors -error: - denied_command: '&cZa uporabo ukazov se je potrebno prijaviti!' - denied_chat: '&cZa pogovor se je potrebno prijaviti!' - unregistered_user: '&cNi mogoče najti zahtevanega uporabnika v podatkovni bazi!' - not_logged_in: '&cNiste prijavljeni!' - no_permission: '&4Nimate dovoljenja za izvedbo tega dejanja!' - unexpected_error: '&4Prišlo je do nepričakovane napake, prosim kontaktirajte administratorja!' - max_registration: '&cPresegli ste največjo stevilo registracij (%reg_count/%max_acc %reg_names) za vašo povezavo!' - logged_in: '&cSte že povezani!' - kick_for_vip: '&3VIP igralec se je pridruzil serverju, ko je bil poln!' - kick_unresolved_hostname: '&cPrišlo je do napake: ime gostitelja igralca ni razrešeno!' - tempban_max_logins: '&cBil si začasno izločen zaradi preveč neuspešnih prijav.' - -# AntiBot -antibot: - kick_antibot: 'Počakajte nekaj minut preden se povezete na strežnik.' - auto_enabled: '&4[AntiBotService] AntiBot je bil aktiviran zaradi velikega števila prijav!' - auto_disabled: '&2[AntiBotService] AntiBot je bil deaktiviran po %m minut!' - -# Unregister -unregister: - success: '&cUsprešno deregistriran!' - command_usage: '&cUporaba: /unregister ' - -# Other messages -misc: - account_not_activated: '&cVas račun se ni aktiviran, preverite e-mail!' - not_activated: '&cRačun ni aktiviran, prosimo, registrirajte se in ga aktivirajte, preden poskusite znova.' - password_changed: '&2Geslo uspesno spremenjeno!' - logout: '&2Odjavljeni uspesno!' - reload: '&2Konfiguracija in baza podatkov sta bila uspesno osvezena!' - usage_change_password: '&cUporaba: /changepassword ' - accounts_owned_self: 'You own %count accounts:' - accounts_owned_other: 'The player %name has %count accounts:' - -# Session messages -session: - valid_session: '&2Uspešna povezava.' - invalid_session: '&cVas IP je bil spremenjen in vasa seja je potekla!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Igralec z enakim IP-jem kot vi je že v igri.' - same_nick_online: '&4Uporabnik z enakim imenom ze igra!' - name_length: '&4Vaše uporabniško ime je prekratko ali predolgo!' - characters_in_name: '&4Vaše uporabniško ime vsebuje nedovoljene znake. Dovoljeni znaki: %valid_chars' - kick_full_server: '&4Streznik je trenutno poln!' - country_banned: '&4Vaša država je prepovedana na strežniku!' - not_owner_error: 'Niste lastnik tega uporabniškega računa. Izberite drugo uporabnisko ime!' - invalid_name_case: 'Povežite se z uporabo uporabniskega imena %valid in ne %invalid.' - quick_command: 'Komando ste uporabili prehitro! Prosimo, da se ponovno povežete in počakate pred ponovno uporabo komand.' - -# Email -email: - add_email_request: '&3Dodajte email vašemu računu z ukazom "/email add "' - usage_email_add: '&cUporaba: /email add ' - usage_email_change: '&cUporaba: /email change ' - new_email_invalid: '&cNeveljaven nov email, poskusite ponovno!' - old_email_invalid: '&cNeveljaven star email, poskusite ponovno!' - invalid: '&cNapačni email!' - added: '&2Email uspešno dodan!' - add_not_allowed: '&cDodajanje emailov ni dovoljeno!' - request_confirmation: '&cPotrdite vaš email naslov.' - changed: '&2Email uspešno spremenjen!' - change_not_allowed: '&cSpreminjanje emailov ni dovoljeno.' - email_show: '&2Vaš trenuten email: &f%email' - no_email_for_account: '&2Trenutno nimate povezanega emaila.' - already_used: '&4Ta email naslov je že v uporabi!' - incomplete_settings: 'Napaka: Administrator ni nastavil vseh nastavitev za pošiljanje emailov. Prosimo, da ga obvestite.' - send_failure: 'Emaila ni bilo mogoče poslati. Prosimo obvestite administratorja.' - change_password_expired: 'Prosim uporabite novi ukaz.' - email_cooldown_error: '&cSporočilo je bilo že poslano. Pocakajte %time preden zahtevate novega!' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Ste pozabili vaše geslo? Uporabite ukaz "/email recovery "' - command_usage: '&cUporaba: /email recovery ' - email_sent: '&2Email za obnovitev uspešno poslan! Preverite prejeta email sporočila! Preverite tudi Spam/Vsiljeno pošto!' - code: - code_sent: 'Koda za ponastavitev gesla je bila poslana na vaš email.' - incorrect: 'Koda je nepravilna! Uporabite /email recovery [Email], da pridobite novo kodo.' - tries_exceeded: 'Prekoračili ste število poskusov! Uporabite /email recovery [Email], da pridobite novo kodo.' - correct: 'Uspešno vnesena koda!' - change_password: 'Prosim uporabite /email setpassword za nastavitev novega gesla.' - -# Captcha -captcha: - usage_captcha: '&3Da se prijavite rešite captcha kodo, uporabite ukaz "/captcha %captcha_code"' - wrong_captcha: '&cNapačna captcha, vpišite "/captcha %captcha_code" v chat!' - valid_captcha: '&2Captcha pravilno rešena!' - captcha_for_registration: 'Za registracijo morate prvo rešiti captcha. Uporabite: /captcha %captcha_code' - register_captcha_valid: '&2Pravilna captcha! Sedaj se lahko registrirate z /register' - -# Verification code -verification: - code_required: '&3Ta ukaz je lahko tvegan in zahteva preverjanje preko emaila. Preverite email za dodatna navodila.' - command_usage: '&cUporabite: /verification ' - incorrect_code: '&cIncorrect code, please type "/verification " into the chat, using the code you received by email' - success: '&2Your identity has been verified! You can now execute all commands within the current session!' - already_verified: '&2You can already execute every sensitive command within the current session!' - code_expired: '&3Your code has expired! Execute another sensitive command to get a new code!' - email_needed: '&3To verify your identity you need to link an email address with your account!' - -# Time units -time: - second: 'sekunda' - seconds: 'sekund' - minute: 'minuta' - minutes: 'minut' - hour: 'ur' - hours: 'ure' - day: 'dan' - days: 'dni' - -# Two-factor authentication -two_factor: - code_created: '&2Vasa skrivna koda je %code. Lahko je skenirate tu %url!' - confirmation_required: 'Prosimo, da potrdite svojo dvo stopično kodo z /2fa confirm ' - code_required: 'Prosimo, da pošljete svojo dvo stopično kodo z /2fa code ' - already_enabled: 'Dvo stopična prijava je že vključena za vaš račun!' - enable_error_no_code: 'Nobeden dvo stopični ključ ni bil generiran za vaš račun ali pa je potekel. Uporabite /2fa add' - enable_success: 'Usprešno ste vključili dvo stopično prijavo za vaš račun.' - enable_error_wrong_code: 'Napačna koda ali pa je potekla. Uporabite /2fa add' - not_enabled_error: 'Dvo stopična prijava ni vključena za vaš račun. Uporabite /2fa add' - removed_success: 'Usprešno ste odstranili dvo stopično prijavo za vaš račun.' - invalid_code: 'Nepravilna koda!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aSamodejno prijavljanje v Bedrocku uspešno!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aMed prijavo ste obtičali v portalu.' - fix_underground: '&aMed prijavo ste obtičali pod zemljo.' - cannot_fix_underground: '&aMed prijavo ste obtičali pod zemljo, vendar tega ne moremo popraviti.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cBili ste odklopljeni zaradi podvojenega prijave.' diff --git a/src/main/resources/messages/messages_sk.yml b/src/main/resources/messages/messages_sk.yml deleted file mode 100644 index fd40f0de..00000000 --- a/src/main/resources/messages/messages_sk.yml +++ /dev/null @@ -1,179 +0,0 @@ -# Slovak translate by: Judzi 2.2.2013 # -# Next Translation & Correction by: # -# Thymue 7.8.2017 # -# in future there can be more translators # -# if they are not listed here # -# check Translators on GitHub Wiki. # -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cRegistrácia nie je povolená.' - name_taken: '&cZadané meno je už zaregistrované.' - register_request: '&cZaregistruj sa príkazom "/register ".' - command_usage: '&cPoužitie: /register ' - reg_only: '&fIba zaregistrovaný hráči sa môžu pripojiť na tento server! Navštív https://example.com pre registráciu.' - success: '&cBol si úspešne zaregistrovaný.' - kicked_admin_registered: 'Admin ťa zaregistroval. Prosím, prihlás sa znovu.' - -# Password errors on registration -password: - match_error: '&fHeslá sa nezhodujú.' - name_in_password: '&cNemôžeš použiť tvoje meno ako heslo. Prosím, zvoľ si iné...' - unsafe_password: '&cTvoje heslo nieje bezpečné. Prosím, zvoľ si iné...' - forbidden_characters: '&4Tvoje heslo obsahuje zakázané znaky. Povolené znaky: %valid_chars' - wrong_length: '&fHeslo je veľmi krátke alebo veľmi dlhé.' - pwned_password: '&cVaše zvolené heslo nie je bezpečné. Bolo použité %pwned_count krát! Prosím, použite silné heslo...' - -# Login -login: - command_usage: '&cPoužitie: /login ' - wrong_password: '&cZadal si zlé heslo.' - success: '&cBol si úspešne prihlásený!' - login_request: '&cPrihlás sa príkazom "/login ".' - timeout_error: '&fVypršal čas na prihlásenie, pripoj sa a skús to znovu.' - -# Errors -error: - denied_command: '&cPre použitie tohto príkazu sa musíš prihlásiť!' - denied_chat: '&cMusíš byť prihlásený ak chceš použiť chat!' - unregistered_user: '&cZadané meno nie je zaregistrované!' - not_logged_in: '&cEšte nie si prihlásený!' - no_permission: '&cNemáš dostatočné práva na vykonanie tejto činnosti.' - unexpected_error: '&fNastala chyba, prosím kontaktuj Administrátora.' - max_registration: '&fPrekročil si maximum registrovaných účtov(%reg_count/%max_acc|%reg_names).' - logged_in: '&cAktuálne si už prihlásený!' - kick_for_vip: '&3Uvoľnil si miesto pre VIP hráča!' - kick_unresolved_hostname: '&cDošlo k chybe: nerozpoznaný hostname hráča!' - tempban_max_logins: '&cBol si dočasne zabanovaný za opakované zadanie zlého hesla.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot je zapnutý! Musíš počkať niekoľko minút pred znovupripojením sa na server.' - auto_enabled: '&4[AntiBotService] AntiBot bol zapnutý kôli masívnym pokusom o pripojenie!' - auto_disabled: '&2[AntiBotService] AntiBot bol vypnutý po %m minútach!' - -# Unregister -unregister: - success: '&cÚčet bol vymazaný!' - command_usage: '&cPoužitie: /unregister heslo' - -# Other messages -misc: - account_not_activated: '&fTvoj účet nie je aktivovaný. Prezri si svoj e-mail!' - not_activated: '&cÚčet nie je aktivovaný, prosím, zaregistrujte sa a aktivujte ho pred pokusom o prihlásenie znova.' - password_changed: '&cHeslo zmenené!' - logout: '&cBol si úspešne odhlásený.' - reload: '&fZnovu načítanie konfigurácie a databázy bolo úspešné.' - usage_change_password: '&fPoužitie: /changepassword ' - accounts_owned_self: 'Vlastníš tieto účty(%count): ' - accounts_owned_other: 'Hráč %name vlastní tieto účty(%count): ' - -# Session messages -session: - valid_session: '&cAutomatické prihlásenie z dôvodu pokračovania relácie.' - invalid_session: '&fTvoja IP sa zmenila a tvoje prihlásenie(relácia) vypršalo(/a).' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Hráč s tvojou IP už hrá na tomto serveri!' - same_nick_online: '&fHráč s týmto nickom už hrá!' - name_length: '&cTvoje meno je veľmi krátke alebo veľmi dlhé.' - characters_in_name: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: %valid_chars' - kick_full_server: '&4Server je plný, skús to znovu neskôr!' - country_banned: '&4Tvoja krajina je zabanovaná na tomto serveri!' - not_owner_error: 'Nie si majiteľom tohto účtu. Prosím zvoľ si iné meno!' - invalid_name_case: 'Mal by si sa pripojiť s nickom %valid, nie %invalid - pozor na veľké a malé písmená.' - quick_command: 'Príkaz ste použili príliš rýchlo! Prosím, znovu sa pripojte na server a počkajte dlhšie pred použitím akéhokoľvek príkazu.' - -# Email -email: - add_email_request: '&cPridaj svoj e-mail príkazom "/email add ".' - usage_email_add: '&cPoužitie: /email add ' - usage_email_change: '&cPoužitie: /email change ' - new_email_invalid: '&cNeplatný nový email, skús to znovu!' - old_email_invalid: '&cNeplatný starý email, skús to znovu!' - invalid: '&cNeplatná emailová adresa, skús to znovu!' - added: '&2Emailová adresa bola úspešne pridaná k tvojmu účtu!' - add_not_allowed: '&cPridanie emailu nebolo povolené.' - request_confirmation: '&cProsím potvrď svoju emailovú adresu!' - changed: '&2Emailová adresa bola úspešne zmenená!' - change_not_allowed: '&cZmena emailu nebola povolená.' - email_show: '&2Tvoja súčastná emailová adresa je: &f%email' - no_email_for_account: '&2Momentálne nemáš emailovú adresu spojenú s týmto účtom.' - already_used: '&4Túto emailovú adresu už niekto používa.' - incomplete_settings: 'Chyba: nie všetky potrebné nastavenia sú nastavené pre posielanie emailov. Prosím kontaktuj Administrátora.' - send_failure: 'Email nemohol byť poslaný. Prosím kontaktuj Administrátora.' - change_password_expired: 'Už nemôžeš zmeniť svoje heslo týmto príkazom.' - email_cooldown_error: '&cEmail bol nedávno poslaný. Musíš počkať %time predtým ako ti pošleme nový.' - -# Password recovery by email -recovery: - forgot_password_hint: '&cZabudol si heslo? Použi príkaz /email recovery ' - command_usage: '&cPoužitie: /email recovery ' - email_sent: '&2Email na obnovenie bol úspešne odoslaný! Prosím skontroluj si svoju emailovú schránku!' - code: - code_sent: 'Kód na obnovenie účtu bol poslaný na tvoj e-mail.' - incorrect: 'Nesprávny kód! Zostávajúce pokusy: %count.' - tries_exceeded: 'Prekročil si maximálny počet pokusov o zadanie kódu pre obnovenie účtu. Použi "/email recovery [email]" pre vygenerovanie nového kódu.' - correct: 'Správny kód!' - change_password: 'Prosím hneď použi príkaz /email setpassword pre zmenenie tvojeho hesla.' - -# Captcha -captcha: - usage_captcha: '&3Pre prihlásenie musíš vyriešiť captcha kód, prosím použi príkaz: /captcha %captcha_code' - wrong_captcha: '&cNesprávny kód captcha, prosím napíš "/captcha %captcha_code" do chatu!' - valid_captcha: '&2Správne si vyriešil captcha kód!' - captcha_for_registration: 'Ak sa chcete zaregistrovať, musíte najskôr vyriešiť captcha, prosím, použite príkaz: /captcha %captcha_code' - register_captcha_valid: '&2Platná captcha! Teraz sa môžete zaregistrovať pomocou /register' - -# Verification code -verification: - code_required: '&3Tento príkaz je citlivý a vyžaduje overenie emailom! Skontrolujte svoju schránku a postupujte podľa pokynov v emaile.' - command_usage: '&cPoužitie: /verification ' - incorrect_code: '&cNesprávny kód, prosím, zadajte "/verification " do chatu, pomocou kódu, ktorý ste dostali emailom' - success: '&2Vaša identita bola overená! Teraz môžete vykonávať všetky príkazy v rámci aktuálnej relácie!' - already_verified: '&2Už môžete vykonávať každý citlivý príkaz v rámci aktuálnej relácie!' - code_expired: '&3Váš kód vypršal! Vykonajte ďalší citlivý príkaz na získanie nového kódu!' - email_needed: '&3Na overenie vašej identity potrebujete prepojiť emailovú adresu so svojím účtom!!' - -# Time units -time: - second: 'sek.' - seconds: 'sek.' - minute: 'min.' - minutes: 'min.' - hour: 'hod.' - hours: 'hod.' - day: 'd.' - days: 'd.' - -# Two-factor authentication -two_factor: - code_created: '&2Tvoj tajný kód je %code. Môžeš ho oskenovať tu: %url' - confirmation_required: 'Prosím, potvrďte svoj kód pomocou /2fa confirm ' - code_required: 'Prosím, zadajte svoj dvojfaktorový autentifikačný kód pomocou /2fa code ' - already_enabled: 'Dvojfaktorová autentifikácia je už pre váš účet povolená!' - enable_error_no_code: 'Nebolo pre vás vygenerované žiadne 2fa kľúč alebo vypršal jeho platnosť. Prosím, použite príkaz /2fa add' - enable_success: 'Dvojfaktorová autentifikácia bola úspešne povolená pre váš účet' - enable_error_wrong_code: 'Nesprávny kód alebo kód vypršal. Prosím, použite príkaz /2fa add' - not_enabled_error: 'Dvojfaktorová autentifikácia nie je pre váš účet povolená. Použite príkaz /2fa add' - removed_success: 'Dvojfaktorová autentifikácia bola úspešne odstránená z vášho účtu' - invalid_code: 'Neplatný kód!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aAutomatické prihlásenie do Bedrocku úspešné!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aPočas prihlasovania ste uviazli v portáli.' - fix_underground: '&aPočas prihlasovania ste uviazli pod zemou.' - cannot_fix_underground: '&aPočas prihlasovania ste uviazli pod zemou, ale nemôžeme to opraviť.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cBoli ste odpojení kvôli zdvojenému prihláseniu.' diff --git a/src/main/resources/messages/messages_sr.yml b/src/main/resources/messages/messages_sr.yml deleted file mode 100644 index e143f6b2..00000000 --- a/src/main/resources/messages/messages_sr.yml +++ /dev/null @@ -1,173 +0,0 @@ -# Lista globalnih tagova: -# %nl% - Nova linija. -# %username% - Zamenjuje ime igrača kome se šalje poruka. -# %displayname% - Zamenjuje nadimak (i boje) igrača kome se šalje poruka. - -# Registration -registration: - disabled: '&cRegistracija u igri je isključena!' - name_taken: '&cKorisnik je već registrovan!' - register_request: '&3Molimo Vas, registrujte se na server komandom: /register ' - command_usage: '&cUpotreba: /register ' - reg_only: '&4Samo registrovani igrači mogu ući na server! Molimo Vas posetite https://example.com da biste se registrovali!' - success: '&2Uspešno registrovani!' - kicked_admin_registered: 'Admin vas je upravo registrovao; molimo Vas uđite ponovo' - -# Password errors on registration -password: - match_error: '&cLozinke se nisu složile, proverite ih ponovo!' - name_in_password: '&cNe možete koristiti svoje ime za lozinku, molimo vas da izaberete drugu...' - unsafe_password: '&cIzabrana lozinka nije bezbedna, molimo vas da izaberete drugu...' - forbidden_characters: '&4Vaša lozinka sadrži nedozvoljene karaktere. Dozvoljeni karakteri: %valid_chars' - wrong_length: '&cVaša lozinka je prekratka ili predugačka! Molimo Vas da probate drugu!' - pwned_password: '&cVaša izabrana lozinka nije sigurna. Već je korišćena %pwned_count puta! Molimo koristite jaku lozinku...' - -# Login -login: - command_usage: '&cUpotreba: /login ' - wrong_password: '&cPogrešna lozinka!' - success: '&2Uspešno ste se ulogovali!' - login_request: '&cMolimo Vas, ulogujte se komandom: /login ' - timeout_error: '&4Vreme za login isteklo, izbačeni ste sa servera, molimo Vas da pokušate ponovo!' - -# Errors -error: - denied_command: '&cDa biste koristili komande morate se autentifikovati!' - denied_chat: '&cDa biste koristili čet morate se autentifikovati!' - unregistered_user: '&cKorisnik nije registrovan!' - not_logged_in: '&cNiste ulogovani!' - no_permission: '&4Nemate dovoljno dozvola da uradite to!' - unexpected_error: '&4Pojavila se neočekivana greška, molimo Vas kontaktirajte administratora!' - max_registration: '&cDostigli ste maksimalan broj registracija (%reg_count/%max_acc %reg_names) za vaše povezivanje!' - logged_in: '&cVeć ste ulogovani!' - kick_for_vip: '&3VIP igrač je ušao na server dok je bio pun!' - kick_unresolved_hostname: '&cDošlo je do greške: nerešeno ime domaćina igrača!' - tempban_max_logins: '&cPrivremeno ste banovani zbog previše pogrešnih pokušaja ulogovanja.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot mod zaštite je aktiviran! Morate sačekati par minuta pre povezivanja na server.' - auto_enabled: '&4[AntiBotSlužba] AntiBot je aktiviran zbog prevelikog broja povezivanja!' - auto_disabled: '&2[AntiBotSlužba] AntiBot je isključen posle %m minut(a)!' - -# Unregister -unregister: - success: '&cUspešno odregistrovani!' - command_usage: '&cUpotreba: /unregister ' - -# Other messages -misc: - account_not_activated: '&cVaš nalog još uvek nije aktiviran, molimo Vas proverite svoj email!' - not_activated: '&cNalog nije aktiviran, molimo registrujte se i aktivirajte pre nego što pokušate ponovo.' - password_changed: '&2Lozinka uspešno promenjena!' - logout: '&2Uspešno ste se odlogovali!' - reload: '&2Konfiguracija i databaza su uspešno osveženi!' - usage_change_password: '&cUpotreba: /changepassword ' - accounts_owned_self: 'Vi imate %count naloga:' - accounts_owned_other: 'Igrač %name ima %count naloga:' - -# Session messages -session: - valid_session: '&2Ulogovani ste zbog ponovnog povezivanja sesije.' - invalid_session: '&cVaš IP je promenjen i vaši podaci o sesiji su istekli!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Igrač sa istim IP-em je već u igri!' - same_nick_online: '&4Isto korisničko ime već igra na serveru!' - name_length: '&4Vaše korisničko ime je prekratko ili predugačko!' - characters_in_name: '&4Vaše korisničko ime sadrži nedozvoljene karaktere. Dozvoljeni karakteri: %valid_chars' - kick_full_server: '&4Server je pun, probajte ponovo kasnije!' - country_banned: '&4Vaša država je banovana sa ovog servera!' - not_owner_error: 'Ne posedujete ovaj nalog. Molimo Vas izaberite drugo ime!' - invalid_name_case: 'Morate ući sa korisničkim imenom %valid, umesto %invalid.' - quick_command: 'Iskoristili ste komandu previše brzo! Molimo Vas, uđite opet na server i sačekajte malo pre korišćenja komandi.' - -# Email -email: - add_email_request: '&3Molimo Vas dodajte email adresu na vaš nalog komandom: /email add ' - usage_email_add: '&cUpotreba: /email add ' - usage_email_change: '&cUpotreba: /email change ' - new_email_invalid: '&cNevažeći email, pokušajte ponovo!' - old_email_invalid: '&cNevažeći stari email, pokušajte ponovo!' - invalid: '&cNevažeći email, pokušajte ponovo!' - added: '&2Email adresa je uspešno dodata na vaš nalog!' - add_not_allowed: '&cDodavanje emaila nije dozvoljeno' - request_confirmation: '&cMolimo Vas podvrdite svoju email adresu!' - changed: '&2Email adresa uspešno promenjena!' - change_not_allowed: '&cPromena emaila nije dozvoljena' - email_show: '&2Vaša email adresa je: &f%email' - no_email_for_account: '&2Trenutno nemate email adresu povezanu sa svojim nalogom.' - already_used: '&4Email adresa je već u upotrebi' - incomplete_settings: 'Greška: nisu postavljena potrebna podešavanja za slanje emaila. Molimo Vas da kontaktirate admina.' - send_failure: 'Email se nije mogao poslati. Molimo Vas da kontaktirate administratora.' - change_password_expired: 'Ne možete više promeniti svoju lozinku koristeći ovu komandu.' - email_cooldown_error: '&cEmail je već poslat. Morate sačekati %time pre nego što možete poslati drugi.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Zaboravili ste lozinku? Molimo Vas ukucajte komandu: /email recovery ' - command_usage: '&cUpotreba: /email recovery ' - email_sent: '&2Email za povratak je poslat uspešno! Molimo Vas proverite inbox svog emaila!' - code: - code_sent: 'Povratni kod za resetovanje vaše lozinke je poslat na vaš email.' - incorrect: 'Povratni kod nije tačan! Imate još %count pokušaja.' - tries_exceeded: 'Dostigli ste maksimalni broj pokušaja povratka sa kodom. Koristite "/email recovery [email]" da generišite nov.' - correct: 'Povratni kod uspešno unesen!' - change_password: 'Molimo Vas iskoristite komandu /email setpassword da odmah promenite svoju lozinku.' - -# Captcha -captcha: - usage_captcha: '&3Da biste se ulogovali morate rešiti captcha kod, molimo Vas iskoristite komandu: /captcha %captcha_code' - wrong_captcha: '&cPogrešna captcha, molimo Vas kucajte "/captcha %captcha_code" u četu!' - valid_captcha: '&2Captcha kod uspešno unesen!' - captcha_for_registration: 'Da biste se registrovali morate rešiti captcha kod, molimo Vas iskoristite komandu: /captcha %captcha_code' - register_captcha_valid: '&2Ispravna captcha! Sada se možete registrovati koristeći /register' - -# Verification code -verification: - code_required: '&3Ova komanda je osetljiva i zahteva verifikaciju emaila! Molimo Vas proverite svoj inbox i pratite instrukcije u emailu.' - command_usage: '&cUpotreba: /verification ' - incorrect_code: '&cNeispravan kod, molimo Vas unesite "/verification " u čet, koristeći kod koji ste dobili u emailu' - success: '&2Vaš identitet je verifikovan! Sada možete koristiti sve komande u trenutnoj sesiji!' - already_verified: '&2Već možete koristiti sve osetljive komande u trenutnoj sesiji!' - code_expired: '&3Vaš kod je istekao! Iskoristite drugu osetljivu komandu da dobijete kod!' - email_needed: '&3Da biste verifikovali svoj identitet morate da povežete svoju email adresu sa svojim nalogom!!' - -# Time units -time: - second: 'sekund' - seconds: 'sekundi' - minute: 'minut' - minutes: 'minuta' - hour: 'čas' - hours: 'časova' - day: 'dan' - days: 'dana' - -# Two-factor authentication -two_factor: - code_created: '&2Vaš tajni kod je %code. Možete ga skenirati sa %url' - confirmation_required: 'Molimo Vas potvrdite svoj kod koristeći /2fa confirm ' - code_required: 'Molimo Vas unesite svoj autentifikacioni kod dva-faktora koristeći /2fa code ' - already_enabled: 'Autentifikacioni dupli-faktor je već aktiviran za vaš nalog!' - enable_error_no_code: 'Nijedan 2fa ključ nije generisan za vas ili je istekao. Molimo Vas kucajte /2fa add' - enable_success: 'Uspešno ste aktivirali dvo-faktornu autentifikaciju za vaš nalog' - enable_error_wrong_code: 'Pogrešan kod ili je kod istekao. Molimo Vas kucajte /2fa add' - not_enabled_error: 'Dvo-faktorna autentifikacija nije aktivirana za vaš nalog. Kucajte /2fa add' - removed_success: 'Uspešno ste uklonili dvo-faktornu autentifikaciju sa vašeg naloga' - invalid_code: 'Nevažeći kod!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock automatsko prijavljivanje uspešno!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aZaglavljeni ste u portalu tokom prijavljivanja.' - fix_underground: '&aZaglavljeni ste pod zemljom tokom prijavljivanja.' - cannot_fix_underground: '&aZaglavljeni ste pod zemljom tokom prijavljivanja, ali ne možemo to popraviti.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cPrekinuti ste zbog duplog prijavljivanja.' diff --git a/src/main/resources/messages/messages_tr.yml b/src/main/resources/messages/messages_tr.yml deleted file mode 100644 index b9d12bf9..00000000 --- a/src/main/resources/messages/messages_tr.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cOyun icin kayit olma kapatildi!' - name_taken: '&cSenin adinda daha once birisi kaydolmus!' - register_request: '&3Lutfen kayit komutunu kullanin "/register "' - command_usage: '&cKullanim: /register ' - reg_only: '&4Sunucuya kayit sadece internet uzerinden yapilmakta! Lutfen https://ornek.com sitesini kayit icin ziyaret edin!' - success: '&2Basariyla kaydoldun!' - kicked_admin_registered: 'Bir yetkili seni kayit etti; tekrardan giris yap' - -# Password errors on registration -password: - match_error: '&cSifre eslesmiyor, tekrar deneyin!' - name_in_password: '&cSifrenize adinizi koyamazsiniz, lutfen farkli bir sifre secin...' - unsafe_password: '&cSectiginiz sifre guvenli degil, lutfen farkli bir sifre secin...' - forbidden_characters: '&4Sifrenizde izin verilmeyen karakterler bulunmakta. Izin verilen karakterler: %valid_chars' - wrong_length: '&cSenin sifren ya cok kisa yada cok uzun! Lutfen farkli birsey dene!' - pwned_password: '&cSeçtiğiniz şifre güvenli değil. Zaten %pwned_count kez kullanılmış! Lütfen güçlü bir şifre kullanın...' - -# Login -login: - command_usage: '&cKullanim: /login ' - wrong_password: '&cYanlis sifre!' - success: '&2Giris basarili!' - login_request: '&cLutfen giris komutunu kullanin "/login "' - timeout_error: '&4Giris izni icin verilen zaman suresini astigin icin sunucudan atildin, tekrar deneyin!' - -# Errors -error: - denied_command: '&cSuanda bu komutu kullanamazsin!' - denied_chat: '&cSuanda sohbeti kullanamazsin!' - unregistered_user: '&cBu oyuncu kayitli degil!' - not_logged_in: '&cGiris yapmadin!' - no_permission: '&4Bunu yapmak icin iznin yok!' - unexpected_error: '&4Beklenmedik bir hata olustu, yetkili ile iletisime gecin!' - max_registration: '&cSen maksimum kayit sinirini astin (%reg_count/%max_acc %reg_names)!' - logged_in: '&cZaten giris yaptin!' - kick_for_vip: '&3Bir VIP oyuna giris yaptigi icin atildin!' - kick_unresolved_hostname: '&cBir hata olustu: cozumlenemeyen oyuncu bilgisayar adi!' - tempban_max_logins: '&cBir cok kez yanlis giris yaptiginiz icin gecici olarak banlandiniz.' - -# AntiBot -antibot: - kick_antibot: 'AntiBot koruma modu aktif! Birkac dakika sonra tekrar girmeyi deneyin.' - auto_enabled: '&4[AntiBotServis] Saldiri oldugu icin AntiBot aktif edildi!' - auto_disabled: '&2[AntiBotServis] AntiBot, %m dakika sonra deaktif edilecek!' - -# Unregister -unregister: - success: '&cKayit basariyla kaldirildi!' - command_usage: '&cKullanim: /unregister ' - -# Other messages -misc: - account_not_activated: '&cHeabiniz henuz aktif edilmemis, e-postanizi kontrol edin!' - not_activated: '&cHesap aktif değil, lütfen tekrar denemeden önce kaydolun ve aktif hale getirin.' - password_changed: '&2Sifre basariyla degistirildi!' - logout: '&2Basariyla cikis yaptin!' - reload: '&2Ayarlar ve veritabani yenilendi!' - usage_change_password: '&cKullanim: /changepassword ' - accounts_owned_self: 'Sen %count hesaba sahipsin:' - accounts_owned_other: 'Oyuncu %name %count hesaba sahip:' - -# Session messages -session: - valid_session: '&2Oturuma girisiniz otomatikmen yapilmistir.' - invalid_session: '&cIP adresin degistirildi ve oturum suren doldu!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Oyunda sizin ipnizden giren biri bulunmakta!' - same_nick_online: '&4Senin isminde bir oyuncu suncuda bulunmakta!' - name_length: '&4Senin ismin ya cok kisa yada cok uzun!' - characters_in_name: '&4Senin isminde uygunsuz karakterler bulunmakta. Izin verilen karakterler: %valid_chars' - kick_full_server: '&4Sunucu suanda dolu, daha sonra tekrar deneyin!' - country_banned: '&4Senin bolgen sunucudan yasaklandi!' - not_owner_error: 'Bu hesabin sahibi degilsin. Lutfen farkli bir isim sec!' - invalid_name_case: 'Oyuna %valid isminde katilmalisin. %invalid ismini kullanarak katilamazsin.' - quick_command: 'Bu komutu cok hizli kullandin! Lutfen, sunucuya tekrar gir ve herhangi bir komut kullanmadan once biraz bekle.' - -# Email -email: - add_email_request: '&3Lutfen hesabinize eposta adresinizi komut ile ekleyin "/email add "' - usage_email_add: '&cKullanim: /email add ' - usage_email_change: '&cKullanim: /email change ' - new_email_invalid: '&cGecersiz yeni eposta, tekrar deneyin!' - old_email_invalid: '&cGecersiz eski eposta, tekrar deneyin!' - invalid: '&cGecersiz eposta, tekrar deneyin!' - added: '&2Eposta basariyla kullaniciniza eklendi!' - add_not_allowed: '&cE-posta eklenmesine izin verilmedi!' - request_confirmation: '&cLutfen tekrar epostanizi giriniz!' - changed: '&2Epostaniz basariyla degistirildi!' - change_not_allowed: '&cEposta degistirilmesine izin verilmedi!' - email_show: '&2Suanki eposta adresin: &f%email' - no_email_for_account: '&2Bu hesapla iliskili bir eposta bulunmuyor.' - already_used: '&4Eposta adresi zaten kullaniliyor.' - incomplete_settings: 'Hata: Gonderilen epostada bazi ayarlar tamamlanmis degil. Yetkili ile iletisime gec.' - send_failure: 'Eposta gonderilemedi. Yetkili ile iletisime gec.' - change_password_expired: 'Artik bu komutu kullanarak sifrenizi degistiremezsiniz.' - email_cooldown_error: '&cKisa bir sure once eposta gonderildi. Yeni bir eposta almak icin %time beklemelisin.' - -# Password recovery by email -recovery: - forgot_password_hint: '&3Sifreni mi unuttun ? Komut kullanarak ogrenebilirsin "/email recovery "' - command_usage: '&cKullanim: /email recovery ' - email_sent: '&2Sifreniz epostaniza gonderildi! Lutfen eposta kutunuzu kontrol edin!' - code: - code_sent: 'Sifre sifirlama kodu eposta adresinize gonderildi.' - incorrect: 'Kod dogru degil! Kullanim "/email recovery [eposta]" ile yeni bir kod olustur' - tries_exceeded: 'Kurtarma kodu icin girilen maksimum sayisi astiniz. "/email recovery [email]" komutunu kullanarak yeni bir tane olusturabilirsiniz.' - correct: 'Kurtarma kodu dogru sekilde girildi!' - change_password: 'Lutfen sifrenizi degistirmek icin /email setpassword komutunu kullanin.' - -# Captcha -captcha: - usage_captcha: '&3Giris yapmak icin guvenlik kodunu komut yazarak girin "/captcha %captcha_code"' - wrong_captcha: '&cYanlis guvenlik kodu, kullanim sekli "/captcha %captcha_code" sohbete yazin!' - valid_captcha: '&2Guvenlik kodu dogrulandi!' - captcha_for_registration: 'Kayit olmak icin once bir captcha cozmeniz gerekiyor, lutfen bu komutu kullan: /captcha %captcha_code' - register_captcha_valid: '&2Gecerli captcha! /register ile kayit olabilirsiniz' - -# Verification code -verification: - code_required: '&3Bu komut hassas ve eposta dogrulamasi gerektiriyor! Gelen kutunuzu kontrol edin ve epostalarin talimatlarina uyun.' - command_usage: '&Kullanim: /verification ' - incorrect_code: '&cYanlis kod, lutfen email ile aldiginiz kodu kullanarak, chate "/verification " yazin' - success: '&2Kimliginiz dogrulandi! Simdi mevcut oturumdaki butun komutlari calistirabilirsiniz!' - already_verified: '&2Mevcut oturumda her hassas komutu zaten calistirabilirsiniz!' - code_expired: '&3Kodunuzun suresi doldu! Diger hassas komutlari calistirmak icin yeni bir kod alin!' - email_needed: '&3Kimliginizi dogrulamak icin hesabiniza bir email adresi baglamis olmaniz gerekir!!' - -# Time units -time: - second: 'saniye' - seconds: 'saniye' - minute: 'dakika' - minutes: 'dakika' - hour: 'saat' - hours: 'saat' - day: 'gun' - days: 'gun' - -# Two-factor authentication -two_factor: - code_created: '&2Gizli kodunuz %code. Buradan test edebilirsin, %url' - confirmation_required: 'Lutfen kodunuzu /2fa confirm komutu ile dogrulayin' - code_required: 'Lutfen iki-faktorlu dogrulama kodunuzu /2fa code komutu ile gonderin' - already_enabled: 'Iki-faktorlu dogrulama zaten hesabinizda aktif durumda!' - enable_error_no_code: 'Sizin icin 2fa anahtari olusturulmamis ya da suresi dolmus. Lutfen /2fa add komutunu calistirin' - enable_success: 'Iki-faktorlu kimlik dogrulama hesabiniz icin basariyla aktif edildi' - enable_error_wrong_code: 'Yanlis kod veya kodun suresi dolmus. Lutfen /2fa add komutunu calistirin' - not_enabled_error: 'Iki-faktorlu kimlik dogrulama kodu hesabiniz icin aktif edilmemis. /2fa add komutunu calistirin' - removed_success: 'Iki-faktorlu dogrulama hesabinizdan basariyla kaldirilmistir' - invalid_code: 'Gecersiz kod!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aBedrock otomatik giriş başarılı!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aGiriş sırasında portalda sıkıştınız.' - fix_underground: '&aGiriş sırasında yeraltında sıkıştınız.' - cannot_fix_underground: '&aGiriş sırasında yeraltında sıkıştınız, ancak bunu düzeltemiyoruz.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cÇifte giriş nedeniyle bağlantınız kesildi.' diff --git a/src/main/resources/messages/messages_uk.yml b/src/main/resources/messages/messages_uk.yml deleted file mode 100644 index b16bbb98..00000000 --- a/src/main/resources/messages/messages_uk.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cВнутрішньоігрову реєстрацію зараз вимкнено.' - name_taken: '&cТакий нікнейм вже зареєстровано.' - register_request: '&3Перш ніж почати гру, вам потрібно зареєструвати свій нікнейм!%nl%&3Для цього просто введіть команду "/register <пароль> <повторПароля>"' - command_usage: '&cСинтаксис: /register <пароль> <повторПароля>' - reg_only: '&4Лише зареєстровані гравці можуть підключатись до сервера!%nl%&4Будь ласка, відвідайте https://example.com для реєстрації.' - success: '&2Реєстрація пройшла успішно!' - kicked_admin_registered: 'Адміністратор вас зареєстрував; Будь ласка, авторизуйтесь знову!' - -# Password errors on registration -password: - match_error: '&cПаролі не співпадають!' - name_in_password: '&cНе можна використовувати свій нікнейм у якості пароля! Будь ласка, виберіть щось інакше...' - unsafe_password: '&cЦей пароль надто простий! Будь ласка, придумайте інакший...' - forbidden_characters: '&4Ваш пароль містить недопустимі символи. Підберіть інакший...%nl%&4(Reg-ex: %valid_chars)' - wrong_length: '&cВаш пароль надто короткий або надто довгий! Спробуйте інакший...' - pwned_password: '&cВаш вибраний пароль небезпечний. Він вже використовувався %pwned_count разів! Будь ласка, використовуйте надійний пароль...' - -# Login -login: - command_usage: '&cСинтаксис: /login <пароль>' - wrong_password: '&cНевірний пароль!' - success: '&2Успішна авторизація!' - login_request: '&cДля авторизації, введіть команду "/login <пароль>"' - timeout_error: '&4Час для авторизації сплинув. Будь ласка, спробуйте ще раз!' - -# Errors -error: - denied_command: '&cДля використання цієї команди потрібна авторизація.' - denied_chat: '&cДля доступу до чату потрібна авторизація.' - unregistered_user: '&cЦей гравець не є зареєстрованим.' - not_logged_in: '&cВи не авторизовані!' - no_permission: '&4У вас недостатньо прав, щоб застосувати цю команду!' - unexpected_error: '&4[AuthMe] Помилка. Будь ласка, повідомте адміністратора!' - max_registration: '&cВичерпано ліміт реєстрацій (%reg_count/%max_acc %reg_names) для вашого підключення!' - logged_in: '&cВи вже авторизовані!' - kick_for_vip: '&3Вас кікнуто, внаслідок того, що VIP гравець зайшов на сервер коли небуло вільних місць.' - kick_unresolved_hostname: '&cЗнайдена помилка: невирішене ім''я вузла гравця!' - tempban_max_logins: '&cВаш IP тимчасово заблоковано, із‒за багатократного введення хибного пароля.' - -# AntiBot -antibot: - kick_antibot: 'На сервер здійснено DDoS атаку. Будь ласка, зачекайте декілька хвилин доки активність спаде.' - auto_enabled: '&4[AntiBotService] Ненормативне число з’єднань. Активовано антибот систему!' - auto_disabled: '&2[AntiBotService] Антибот систему деактивовано після %m хв. активності.' - -# Unregister -unregister: - success: '&cДані про реєстрацію успішно видалено' - command_usage: '&cСинтаксис: /unregister <пароль>' - -# Other messages -misc: - account_not_activated: '&cВаш акаунт ще не активовано. Будь ласка, провірте свою електронну пошту!' - not_activated: '&cАкаунт не активовано, будь ласка, зареєструйтесь і активуйте його перед повторною спробою.' - password_changed: '&2Пароль успішно змінено!' - logout: '&2Ви вийшли зі свого акаунта!' - reload: '&2Конфігурації та базу даних було успішно перезавантажено!' - usage_change_password: '&cСинтаксис: /changepassword <старийПароль> <новийПароль>' - accounts_owned_self: 'Кількість ваших твінк‒акаунтів: %count:' - accounts_owned_other: 'Кількість твінк‒акаунтів гравця %name: %count' - -# Session messages -session: - valid_session: '&2Сесію відновлено.' - invalid_session: '&cСесію було розірвано внаслідок зміни IP.' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Перевищено ліміт на авторизацію з одного IP.' - same_nick_online: '&4Хтось з таким ніком зараз вже сидить на сервері!' - name_length: '&4Ваш нікнейм надто короткий або надто довгий!' - characters_in_name: '&4Ваш нікнейм містить недопустимі символи! Reg-ex: %valid_chars' - kick_full_server: '&4Сервер переповнено! Доведеться зачекати доки хтось вийде.' - country_banned: '&4Ваша країна заборонена на цьому сервері!' - not_owner_error: 'Цей акаунт вам не належить! Будь ласка, оберіть інакший нікнейм!' - invalid_name_case: 'Регістр у вашому нікнеймі відрізняється від регістру при реєстрації.%nl%Поточний регістр: &c%invalid&f. Валідний регістр: &a%valid&f.%nl%Будь ласка, перезайдіть з валідним регістром!' - quick_command: 'Ви занадто швидко використовували команду! Будь ласка, приєднайтесь знову до сервера і почекайте, перш ніж використовувати будь-яку команду.' - -# Email -email: - add_email_request: '&3Не забудьте прив’язати електронну пошту до свого акаунта, за допомогою команди "/email add "' - usage_email_add: '&cСинтаксис: /email add ' - usage_email_change: '&cСинтаксис: /email change <старий e-mail> <новий e-mail>' - new_email_invalid: '&cНекоректний формат.' - old_email_invalid: '&cСтарий e-mail, що прив’язано до вашого акаунта, відрізняється від введеного вами.' - invalid: '&cФормат вказаного e-mail’у є некоректним, або його домен внесено до блеклисту.' - added: '&2Електронну пошту успішно прив’язано до вашого акаунта.' - add_not_allowed: '&cДобавлення електронної пошти заборонено' - request_confirmation: '&cАдреси не співпадають.' - changed: '&2E-mail успішно змінено.' - change_not_allowed: '&cЗмiнення пошти заборонено' - email_show: '&2Ваша нинiшня адреса електронної пошти: &f%email' - no_email_for_account: '&2Наразі у вас немає адреси електронної пошти, пов’язаної з цим акаунтом.' - already_used: '&4До цієї електронної пошти прив’язано забагато акаунтів!' - incomplete_settings: '&4Не всі необхідні налаштування є встановленими, щоб надсилати електронну пошту. Будь ласка, повідомте адміністратора!' - send_failure: 'Не вдалося надіслати лист. Зверніться до адміністратора.' - change_password_expired: 'Ви більше не можете змінювати свій пароль, використовуючи цю команду.' - email_cooldown_error: '&cНещодавно вже було надіслано електронний лист. Заждиiть ще %time перш нiж вiдправляти ще листа.' - -# Password recovery by email -recovery: - forgot_password_hint: 'Забули пароль? Можете скористатись командою &9/email recovery &f<&9ваш e-mail&f>' - command_usage: '&cСинтаксис: /email recovery ' - email_sent: '&2Лист для відновлення доступу надіслано. Будь ласка, провірте свою пошту!' - code: - code_sent: 'На вашу адресу електронної пошти надіслано код відновлення для скидання пароля.' - incorrect: 'Код відновлення невірний! У вас залишилось ще %count спроб.' - tries_exceeded: 'Ви перевищили максимальну кількість спроб, щоб ввести код відновлення. Використовуйте "/email recovery [email]" для створення нового запросу.' - correct: 'Код відновлення введено правильно!' - change_password: 'Будь ласка, використовуйте команду /email setpassword <НовийПароль> щоб негайно змінити свій пароль.' - -# Captcha -captcha: - usage_captcha: '&3Для продовження доведеться ввести капчу — "/captcha %captcha_code"' - wrong_captcha: '&cНевірно введена капча! Спробуйте ще раз — "/captcha %captcha_code"' - valid_captcha: '&2Капчу прийнято.' - captcha_for_registration: 'Для того, щоб зареєструвати, ви повинні спочатку вирішити капчу, скористайтеся командою: /captcha %captcha_code' - register_captcha_valid: '&2Ви можете зареєструватися використовуя: /register' - -# Verification code -verification: - code_required: '&3Ця команда вимагає підтвердження електронною поштою! Перевірте свою пошту та дотримуйтесь вказівок у електронному листi.' - command_usage: '&cВикористання: /verification ' - incorrect_code: '&cНеправильний код, введіть "/verification <код>" у чаті, використовуючи код, отриманий електронною поштою' - success: '&2Ваша особа підтверджена! Тепер ви можете виконати всі команди протягом нинiшнього сеансу!' - already_verified: '&2Ви вже можете виконати кожну команду протягом нинiшнього сеансу!' - code_expired: '&3Ваш код закінчився! Виконайте ще одну команду, щоб отримати новий код!' - email_needed: '&3Щоб підтвердити свою особу, вам потрібно зв’язати електронну адресу зі своїм акаунтом!!' - -# Time units -time: - second: 'секунда' - seconds: 'секунд' - minute: 'хвилина' - minutes: 'хвилин' - hour: 'година' - hours: 'годин' - day: 'день' - days: 'днiв' - -# Two-factor authentication -two_factor: - code_created: '&2Ваш секретний код — %code %nl%&2Можете зкопіювати його за цим посиланням — %url' - confirmation_required: 'Підтвердьте свій код за допомогою / 2fa confirm <код>' - code_required: 'Будь ласка, надішліть свій двофакторний код аутентифікації використовуючи: /2fa code ' - already_enabled: 'Для вашого акаунту вже включена двофакторна аутентифікація!' - enable_error_no_code: 'Для вас не створено жодного ключа двухфакторної аутентифiкацii або термін його дії закінчився. Будь ласка, біжи /2fa add' - enable_success: 'Двофакторна автентифікація для вашого акаунта успішно включена' - enable_error_wrong_code: 'Неправильний код або код минув. Будь ласка, використовуйте: /2fa add' - not_enabled_error: 'Двофакторна аутентифікація не включена для вашого акаунту. Використовуйте: /2fa add' - removed_success: 'Двофакторну авторизацію успішно видалено з вашого акаунту' - invalid_code: 'Невірний код!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aАвтоматичний вхід Bedrock успішний!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aВи застрягли в порталі під час входу.' - fix_underground: '&aВи застрягли під землею під час входу.' - cannot_fix_underground: '&aВи застрягли під землею під час входу, але ми не можемо це виправити.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cВас відключено через подвійний вхід.' diff --git a/src/main/resources/messages/messages_vn.yml b/src/main/resources/messages/messages_vn.yml deleted file mode 100644 index 788e5eec..00000000 --- a/src/main/resources/messages/messages_vn.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&cKhông cho phép đăng ký tài khoản trong máy chủ!' - name_taken: '&cTài khoản này đã được đăng ký!' - register_request: '&2Xin vui lòng đăng ký tài khoản với lệnh "/register "' - command_usage: '&cSử dụng: /register ' - reg_only: '&4Chỉ có thành viên mới có thể tham gia máy chủ, vui lòng truy cập trang web https://example.com để đăng ký thành viên!' - success: '&2Đăng ký thành công!' - kicked_admin_registered: 'Một quản trị viên đã đăng ký cho bạn; vui lòng đăng nhập lại' - -# Password errors on registration -password: - match_error: '&cMật khẩu không đúng, vui lòng kiểm tra lại!' - name_in_password: '&cBạn không thể đặt mật khẩu bằng tên của mình, vui lòng đặt lại...' - unsafe_password: '&cMật khẩu của bạn vừa đặt không an toàn, vui lòng đặt lại...' - forbidden_characters: '&4Mật khẩu của bạn chứa ký tự không hợp lệ. Các ký tự cho phép: %valid_chars' - wrong_length: '&cMật khẩu của bạn đặt quá dài hoặc quá ngắn, vui lòng đặt lại!' - pwned_password: '&cMật khẩu bạn chọn không an toàn. Nó đã được sử dụng %pwned_count lần! Vui lòng sử dụng mật khẩu mạnh...' - -# Login -login: - command_usage: '&cSử dụng: /login ' - wrong_password: '&cSai mật khẩu!' - success: '&2Đăng nhập thành công!' - login_request: '&cXin vui lòng đăng nhập bằng lệnh "/login "' - timeout_error: '&4Thời gian đăng nhập đã hết, bạn đã bị văng khỏi máy chủ. Xin vui lòng thử lại!' - -# Errors -error: - denied_command: '&cBạn phải đăng nhập trước rồi mới có thể dùng lệnh này!' - denied_chat: '&cBạn phải đăng nhập trước rồi mới có thể chat!' - unregistered_user: '&cNgười dùng này chưa được đăng ký!' - not_logged_in: '&cBạn chưa đăng nhập!' - no_permission: '&4Bạn không có quyền dùng cập lệnh này!' - unexpected_error: '&4Lỗi! Vui lòng liên hệ quản trị viên.' - max_registration: '&cBạn đã vượt quá giới hạn tối đa đăng ký tài khoản (%reg_count/%max_acc %reg_names) trên đường truyền của bạn!' - logged_in: '&cBạn đã đăng nhập rồi!' - kick_for_vip: '&eChỉ có thành viên VIP mới được tham gia khi máy chủ đầy!' - kick_unresolved_hostname: '&cLỗi đã xảy ra: Không thể phân giải hostname của người chơi!' - tempban_max_logins: '&cBạn đã bị chặn tạm thời do đăng nhập sai quá nhiều lần.' - -# AntiBot -antibot: - kick_antibot: 'Chế độ AntiBot đã được kích hoạt! Bạn phải đợi vài phút trước khi tham gia vào máy chủ.' - auto_enabled: '&4[AntiBotService] AntiBot đã được kích hoạt do số lượng lớn kết nối đến máy chủ!' - auto_disabled: '&2[AntiBotService] AntiBot đã được tắt sau %m phút!' - -# Unregister -unregister: - success: '&cHủy đăng ký thành công!' - command_usage: '&cSử dụng: /unregister ' - -# Other messages -misc: - account_not_activated: '&cTài khoản của bạn chưa được kích hoạt, vui lòng kiểm tra email!' - not_activated: '&cTài khoản chưa được kích hoạt, vui lòng đăng ký và kích hoạt trước khi thử lại.' - password_changed: '&2Thay đổi mật khẩu thành công!' - logout: '&2Bạn đã đăng xuất!' - reload: '&2Cấu hình và cơ sở dử liệu đã được tải lại thành công!' - usage_change_password: '&cSử dụng: /changepassword ' - accounts_owned_self: 'Bạn sở hữu %count tài khoản:' - accounts_owned_other: 'Người chơi %name có %count tài khoản:' - -# Session messages -session: - valid_session: '&2Phiên đăng nhập đã được kết nối trở lại.' - invalid_session: '&cIP của bạn đã bị thay đổi và phiên đăng nhập của bạn đã hết hạn!' - -# Error messages when joining -on_join_validation: - same_ip_online: 'Một người chơi với cùng địa chỉ IP đã kết nối vào máy chủ!' - same_nick_online: '&4Tài khoản đang được sử dụng trên máy chủ!' - name_length: '&4Tên đăng nhập của bạn quá ngắn hoặc quá dài!' - characters_in_name: '&4Tên nhân vật có chứa ký tự không hợp lệ. Các ký tự được cho phép: %valid_chars' - kick_full_server: '&4Máy chủ quá tải, vui lòng thử lại sau!' - country_banned: '&4Quốc gia của bạn bị cấm tham gia máy chủ này!' - not_owner_error: 'Bạn không phải là chủ sở hữu tài khoản này, hãy chọn tên khác!' - invalid_name_case: 'Bạn nên vào máy chủ với tên đăng nhập là %valid, không phải là %invalid.' - quick_command: 'Bạn đang xài lệnh quá nhanh. Hãy thoát máy chủ và chờ một lúc trước khi sử dụng lệnh.' - -# Email -email: - add_email_request: '&eVui lòng thêm email của bạn với lệnh "/email add "' - usage_email_add: '&cSử dụng: /email add ' - usage_email_change: '&cSử dụng: /email change ' - new_email_invalid: '&cEmail mới không hợp lệ, vui lòng thử lại!' - old_email_invalid: '&cEmail cũ không hợp lệ, vui lòng thử lại!' - invalid: '&cĐại chỉ email không hợp lệ, vui lòng thử lại!' - added: '&2Địa chỉ email đã được thêm vào tài khoản của bạn.' - add_not_allowed: '&cKhông được phép thêm địa chỉ email!' - request_confirmation: '&cVui lòng xác nhận địa chỉ email của bạn!' - changed: '&2Địa chỉ email đã thay đổi!' - change_not_allowed: '&cKhông được phép thay đổi địa chỉ email!' - email_show: '&2Địa chỉ email hiện tại của bạn là: &f%email' - no_email_for_account: '&2Hiện tại bạn chưa liên kết bất kỳ email nào với tài khoản này.' - already_used: '&4Địa chỉ email đã được sử dụng!' - incomplete_settings: 'Lỗi: các thiết lập để gửi thư không được cài đặt đúng cách. Vui lòng liên hệ với quản trị viên để báo lỗi.' - send_failure: 'Không thể gửi thư. Vui lòng liên hệ với ban quản trị.' - change_password_expired: '&cBạn không thể thay đổi mật khẩu bằng lệnh này nữa.' - email_cooldown_error: '&cMột email đã được gửi gần đây. Bạn phải chờ %time trước khi có thể gửi một email mới.' - -# Password recovery by email -recovery: - forgot_password_hint: '&aBạn quên mật khẩu? Vui lòng gõ lệnh "/email recovery "' - command_usage: '&cSử dụng: /email recovery ' - email_sent: '&2Email khôi phục đã được gửi thành công! Vui lòng kiểm tra hộp thư đến trong email của bạn.' - code: - code_sent: 'Một mã khôi phục mật khẩu đã được gửi đến địa chỉ email của bạn.' - incorrect: 'Mã khôi phục không đúng! Dùng lệnh /email recovery [email] để tạo một mã mới' - tries_exceeded: 'Bạn đã vượt quá số lần tối đa cho phép nhập mã khôi phục. Hãy sử dụng lệnh "/email recovery [email]" để tạo một mã mới.' - correct: 'Mã khôi phục đã được nhập chính xác!' - change_password: 'Hãy sử dụng lệnh "/email setpassword " để đổi mật khẩu của bạn ngay lập tức.' - -# Captcha -captcha: - usage_captcha: '&eĐể đăng nhập, hãy nhập mã Captcha, Vui lòng gõ lệnh "/captcha %captcha_code"' - wrong_captcha: '&cSai mã captcha, Vui lòng gõ lệnh "/captcha %captcha_code"!' - valid_captcha: '&2Đã xác minh captcha!' - captcha_for_registration: 'Để đăng ký, hãy nhập mã Captcha trước. Vui lòng gõ lệnh "/captcha %captcha_code"' - register_captcha_valid: '&2Đã xác minh captcha! Bây giờ bạn có thể đăng ký với lệnh "/register"' - -# Verification code -verification: - code_required: '&3Lệnh này nhạy cảm và yêu cầu xác minh email! Vui lòng iểm tra hộp thư đến của bạn và làm theo hướng dẫn trong email.' - command_usage: '&cLệnh: /verification ' - incorrect_code: '&cMã xác minh không chính xác, vui lòng nhập "/verify " với mã bạn nhận được qua email.' - success: '&2Xác minh thành công! Bạn đã có thể sử dụng các lệnh trong phiên đăng nhập này.' - already_verified: '&2Bạn đã có thể thực hiện mọi lệnh nhạy cảm trong phiên hiện tại!' - code_expired: '&3Mã xác minh đã hết han! Hãy sử dụng một lệnh nhạy cảm để lấy mã mới.' - email_needed: '&3Để xác định danh tính của bạn, bạn cần kết nối tài khoản này với 1 email!' - -# Time units -time: - second: 'giây' - seconds: 'giây' - minute: 'phút' - minutes: 'phút' - hour: 'giờ' - hours: 'giờ' - day: 'ngày' - days: 'ngày' - -# Two-factor authentication -two_factor: - code_created: '&2Mã bí mật của bạn là %code. Bạn có thể quét nó tại đây %url' - confirmation_required: 'Hãy xác thực mã của bạn bằng lệnh /2fa confirm ' - code_required: 'Hãy nhập mã xác thực 2 lớp của bạn bằng lệnh /2fa code ' - already_enabled: 'Xác thực 2 lớp đã được kích hoạt trên tài khoản của bạn!' - enable_error_no_code: 'Không có mã xác thực nào đã được tạo cho tài khoản của bạn hoặc nó đã hết hạn. Hãy sử dụng lệnh /2fa add' - enable_success: 'Đã thành công kích hoạt xác thực 2 lớp cho tài khoản của bạn!' - enable_error_wrong_code: 'Mã xác thực bị sai hoặc đã bị hết hạn. Hãy sử dụng lệnh /2fa add' - not_enabled_error: 'Xác thực 2 lớp không được kích hoạt trên tài khoản của bạn. Hãy sử dụng lệnh /2fa add' - removed_success: 'Đã thành công tắt xác thực 2 lớp khỏi tài khoản của bạn' - invalid_code: 'Mã xác thực không hợp lệ!' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: '&aĐăng nhập tự động Bedrock thành công!' - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&aBạn bị kẹt trong cổng khi đăng nhập.' - fix_underground: '&aBạn bị kẹt dưới lòng đất khi đăng nhập.' - cannot_fix_underground: '&aBạn bị kẹt dưới lòng đất khi đăng nhập, nhưng chúng tôi không thể khắc phục điều này.' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&cBạn đã bị ngắt kết nối do đăng nhập đôi.' diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml deleted file mode 100644 index 53ad8493..00000000 --- a/src/main/resources/messages/messages_zhcn.yml +++ /dev/null @@ -1,181 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&c注册已被禁止' - name_taken: '&c此用户已经在此服务器注册过' - register_request: '&b请输入“&a/reg <密码> <重复密码>&b”以注册' - command_usage: '&c正确用法:“/reg <密码> <重复密码>”' - reg_only: '&c只允许注册过的玩家进服!' - success: '&a*** 已成功注册 ***' - kicked_admin_registered: '&a*** 管理员刚刚注册了您; 请重新登录 ***' - -# Password errors on registration -password: - match_error: '&c密码不相同' - name_in_password: '&c您不能使用您的名字作为密码。 ' - unsafe_password: '&c您不能使用安全性过低的密码。 ' - forbidden_characters: '&4您的密码包含了非法字符.可使用的字符: %valid_chars' - wrong_length: '&4您的密码没有达到要求!' - pwned_password: '&c你使用的密码并不安全。它已经被使用了 %pwned_count 次! 请使用一个更强大的密码...' - -# Login -login: - command_usage: '&c正确用法:“/l <密码>”' - wrong_password: '&c*** 密码错误 ***' - success: '&a*** 已成功登录 ***' - login_request: '&c请输入“/l <密码>”以登录' - timeout_error: '给您登录的时间已经过了' - -# Errors -error: - denied_command: '&7您需要先通过验证才能使用该命令!' - denied_chat: '&7您需要先通过验证才能聊天!' - unregistered_user: '&c此用户名还未注册过' - not_logged_in: '&c您还未登录!' - no_permission: '&c没有权限' - unexpected_error: '&4发现错误,请联系管理员' - max_registration: '&c该地址已无法注册,请联系管理员进行注册.' - logged_in: '&c您已经登陆过了!' - kick_for_vip: '&c一个VIP玩家加入了已满的服务器!' - kick_unresolved_hostname: '&c发生了一个错误: 无法解析玩家的主机名' - tempban_max_logins: '&c由于您登录失败次数过多,已被暂时禁止登录。' - -# AntiBot -antibot: - kick_antibot: '连接异常,请稍后加入' - auto_enabled: '&c由于发生大量异常连接,本服将禁止连接.' - auto_disabled: '&a异常连接减少,本服将在 &a%m &a分钟后自动开放连接.' - -# Unregister -unregister: - success: '&a*** 已成功注销 ***' - command_usage: '&c正确用法:“/unregister <密码>”' - -# Other messages -misc: - account_not_activated: |- - &a一封包含密码的邮件已发送至您的收件箱. - &a请在十分钟内完成登录,否则将注销此账户. - not_activated: '&c账户未激活,请注册激活后再次尝试.' - password_changed: '&a*** 密码已修改 ***' - logout: '&a*** 已成功登出 ***' - reload: '&a配置以及数据已经重新加载完毕' - usage_change_password: '&a正确用法:“/changepassword 旧密码 新密码”' - accounts_owned_self: '您拥有 %count 个账户:' - accounts_owned_other: '玩家 %name 拥有 %count 个账户:' - -# Session messages -session: - valid_session: '' - invalid_session: '&c*** 请重新登录 ***' - -# Error messages when joining -on_join_validation: - same_ip_online: '已有一个同IP玩家在游戏中了!' - same_nick_online: '&a同样的用户名现在在线且已经登录了!' - name_length: '&c您的用户名太短或者太长了' - characters_in_name: '&c您的用户名不符合标准.' - kick_full_server: '&c抱歉,服务器已满!' - country_banned: |- - &6[&b&lAccount Security System&6] - &c为保证您的游玩体验,请使用中国境内网络连接. - &cTo ensure your play experience,please use the Internet connection within China. - not_owner_error: |- - &6[&b&lAccount Security System&6] - &c请勿尝试登陆系统账户,系统账户受安全系统保护. - &c如果您并不知情,请更换您的用户名重新加入该服务器. - invalid_name_case: '&c您应该使用 %valid 登录服务器,当前名字: %invalid .' - quick_command: '&c您发送命令的速度太快了,请重新加入服务器等待一会后再使用命令' - -# Email -email: - add_email_request: '' - usage_email_add: '&a用法: /email add <邮箱> <确认邮箱> ' - usage_email_change: '&a用法: /email change <旧邮箱> <新邮箱> ' - new_email_invalid: '&c新邮箱无效!' - old_email_invalid: '&c旧邮箱无效!' - invalid: '&c无效的邮箱' - added: '&a*** 邮箱已添加 ***' - add_not_allowed: '&c服务器不允许添加电子邮箱' - request_confirmation: '&c确认您的邮箱' - changed: '&a*** 邮箱已修改 ***' - change_not_allowed: '&c服务器不允许修改邮箱地址' - email_show: '&a该账户使用的电子邮箱为: &a%email' - no_email_for_account: '&c当前并没有任何邮箱与该账号绑定' - already_used: '&c邮箱已被使用' - incomplete_settings: '&c错误: 必要设置未设定完成,请联系管理员' - send_failure: '&c邮件已被作废,请检查您的邮箱是否正常工作.' - change_password_expired: '&c您不能使用此命令更改密码' - email_cooldown_error: '&c您需要等待 %time 后才能再次请求发送' - -# Password recovery by email -recovery: - forgot_password_hint: '&c忘了您的密码?请输入:“/email recovery <您的邮箱>”' - command_usage: '&a用法: /email recovery <邮箱>' - email_sent: '&a找回密码邮件已发送!' - code: - code_sent: '&a*** 已发送验证邮件 ***' - incorrect: '&a验证码不正确! 使用 /email recovery [邮箱] 以生成新的验证码' - tries_exceeded: '&a您已经达到输入验证码次数的最大允许次数.' - correct: '&a*** 验证通过 ***' - change_password: '&c请使用 /email setpassword <新密码> 立即设置新的密码' - -# Captcha -captcha: - usage_captcha: '&7请输入 /captcha %captcha_code 来验证操作.' - wrong_captcha: '&c错误的验证码.' - valid_captcha: '&a*** 验证通过 ***' - captcha_for_registration: '&7请输入 /captcha %captcha_code 来验证操作.' - register_captcha_valid: '&a验证通过, 现在可以使用 /register 注册啦!' - -# Verification code -verification: - code_required: '&a*** 已发送验证邮件 ***' - command_usage: '&c使用方法:/verification <验证码>' - incorrect_code: '&c错误的验证码.' - success: '&a*** 验证通过 ***' - already_verified: '&a您已经通过验证' - code_expired: '&c验证码已失效' - email_needed: '&c邮箱未绑定' - -# Time units -time: - second: '秒' - seconds: '秒' - minute: '分' - minutes: '分' - hour: '时' - hours: '时' - day: '天' - days: '天' - -# Two-factor authentication -two_factor: - code_created: '&7您正在激活双重验证, 请打开 &a%url &7扫描二维码' - confirmation_required: '&7请输入“/totp confirm <验证码>”来确认激活双重验证' - code_required: '&c请输入“/totp code <验证码>”来提交验证码' - already_enabled: '&a双重验证已启用' - enable_error_no_code: '&c验证码丢失' - enable_success: '&a已成功启用双重验证' - enable_error_wrong_code: '&c验证码错误或者已经过期,请重新执行“/totp add”' - not_enabled_error: '&c双重验证未在您的账号上启用,请使用“/totp add”来启用' - removed_success: '&c双重验证已从您的账号上禁用' - invalid_code: '&c无效的验证码' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: "&a基岩版自动登录完成" - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&a你在登录时卡在了地狱门, 现已修正' - fix_underground: '&a你被埋住了, 坐标已修正, 下次下线之前请小心!' - cannot_fix_underground: '&a你被埋住了, 坐标无法修正, 只好送你去了最高点, 自求多福吧少年~' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&a已修复幽灵玩家, 请重新进入' diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml deleted file mode 100644 index 42a96a88..00000000 --- a/src/main/resources/messages/messages_zhhk.yml +++ /dev/null @@ -1,176 +0,0 @@ -# Translator: lifehome # -# Last modif: 1541690611 UTC # -# -------------------------------------------- # -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&8[&6用戶系統&8] &c本伺服器已停止新玩家註冊。' - name_taken: '&8[&6用戶系統&8] &c此用戶名已經註冊過了。' - register_request: '&8[&6用戶系統&8] &c請使用這個指令來註冊:《 &f/register <密碼> <重覆密碼>&c 》' - command_usage: '&8[&6用戶系統&8] &f用法:《 /register <密碼> <重覆密碼> 》' - reg_only: '&8[&6用戶系統&8] &f限已註冊會員,請先到本服網站進行註冊。' - success: '&8[&6用戶系統&8] &b你成功註冊了。' - kicked_admin_registered: '&8[&6用戶系統&8] &b管理員已替你完成註冊,請重新登入。' - -# Password errors on registration -password: - match_error: '&8[&6用戶系統&8] &f密碼不符合。' - name_in_password: '&8[&6用戶系統&8] &c這個密碼太不安全了 !' - unsafe_password: '&8[&6用戶系統&8] &c這個密碼太不安全了 !' - forbidden_characters: '&8[&6用戶系統&8] &4密碼字符只能含有這些喔:%valid_chars' - wrong_length: '&8[&6用戶系統&8] &f嗯... 你的密碼並不符合規定長度。' - pwned_password: '&8[&6用戶系統&8] &c你使用的密碼並不安全。它已經被使用了 %pwned_count 次! 請使用一個更強大的密碼...' - -# Login -login: - command_usage: '&8[&6用戶系統&8] &f用法:《 /login <密碼> 》' - wrong_password: '&8[&6用戶系統&8] &c你輸入了錯誤的密碼。' - success: '&8[&6用戶系統&8] &a你成功登入了。' - login_request: '&8[&6用戶系統&8] &c請使用這個指令來登入:《 &f/login <密碼>&c 》' - timeout_error: '&8[&6用戶系統&8] &f登入逾時。' - -# Errors -error: - denied_command: '&8[&6用戶系統&8] &c請先登入以便使用此指令。' - denied_chat: '&8[&6用戶系統&8] &c請先登入以便與其他玩家聊天。' - unregistered_user: '&8[&6用戶系統&8] &c此用戶名沒有已登記資料。' - not_logged_in: '&8[&6用戶系統&8] &c你還沒有登入 !' - no_permission: '&8[&6用戶系統&8] &b嗯~你想幹甚麼?' - unexpected_error: '&8[&6用戶系統&8] &f發生錯誤,請與管理員聯絡。' - max_registration: '&8[&6用戶系統&8] &f你的IP地址已達到註冊數上限。 &7(info: %reg_count/%max_acc %reg_names)' - logged_in: '&8[&6用戶系統&8] &c你已經登入過了。' - kick_for_vip: '&8[&6用戶系統&8] &c喔 !因為有VIP玩家登入了伺服器。' - kick_unresolved_hostname: '&8[&6用戶系統&8] &c發生了一個錯誤: 無法解析玩家的主機名' - tempban_max_logins: '&8[&6用戶系統&8] &c因為多次登入失敗,你已被暫時封禁。' - -# AntiBot -antibot: - kick_antibot: '&8[&6用戶系統&8] &c伺服器錯誤 !請稍候再嘗試登入吧。 &7(err: kick_due2_bot)' - auto_enabled: '&8[&6用戶系統&8] &3防止機械人程序已因應現時大量不尋常連線而啟用。' - auto_disabled: '&8[&6用戶系統&8] &3不正常連接數已減少,防止機械人程序將於 %m 分鐘後停止。' - -# Unregister -unregister: - success: '&8[&6用戶系統&8] &c已成功刪除會員註冊記錄。' - command_usage: '&8[&6用戶系統&8] &f用法:《 /unregister <密碼> 》' - -# Other messages -misc: - account_not_activated: '&8[&6用戶系統&8] &f你的帳戶還沒有經過電郵驗證 !' - not_activated: '&8[&6用戶系統&8] &c賬戶未激活,請註冊激活後再次嘗試.' - password_changed: '&8[&6用戶系統&8] &c你成功更換了你的密碼 !' - logout: '&8[&6用戶系統&8] &b你成功登出了。' - reload: '&8[&6用戶系統&8] &b登入系統設定及資料庫重新載入完畢。' - usage_change_password: '&8[&6用戶系統&8] &f用法:《 /changepassword <舊密碼> <新密碼> 》' - accounts_owned_self: '你擁有 %count 個帳戶:' - accounts_owned_other: '玩家《%name》擁有 %count 個帳戶:' - -# Session messages -session: - valid_session: '&8[&6用戶系統&8] &b嗨 ! 歡迎回來喔~' - invalid_session: '&8[&6用戶系統&8] &f登入階段資料已損壞,請等待登入階段結束。' - -# Error messages when joining -on_join_validation: - same_ip_online: '&8[&6用戶系統&8] &c你正使用的 IP 位址已被其他玩家佔用。' - same_nick_online: '&8[&6用戶系統&8] &f同名玩家已在遊玩。' - name_length: '&8[&6用戶系統&8] &c你的用戶名不符合規定長度。' - characters_in_name: '&8[&6用戶系統&8] &c用戶名稱錯誤 ! 登入系統只接受以下字符:%valid_chars' - kick_full_server: '&c抱歉 ! 因為伺服器滿人了,所以你目前未能登入伺服器。' - country_banned: '&8[&6用戶系統&8] &c抱歉 !&4本伺服器已停止對你的國家提供遊戲服務。' - not_owner_error: '&8[&6用戶系統&8] &4警告 !&c你並不是此帳戶持有人,請立即登出。' - invalid_name_case: '&8[&6用戶系統&8] &4警告 !&c你應該使用「%valid」而並非「%invalid」登入遊戲。' - quick_command: '&8[&6用戶系統&8] &4警告 !&c你使用指令的速度太快了,請重新登入並稍等一會才再次使用指令。' - -# Email -email: - add_email_request: '&8[&6用戶系統&8] &b請為你的帳戶立即添加電郵地址:《 /email add <電郵地址> <重覆電郵地址> 》' - usage_email_add: '&8[&6用戶系統&8] &f用法:《 /email add <電郵> <重覆電郵> 》' - usage_email_change: '&8[&6用戶系統&8] &f用法:《 /email change <舊電郵> <新電郵> 》' - new_email_invalid: '&8[&6用戶系統&8] &c你所填寫的新電郵地址並不正確。' - old_email_invalid: '&8[&6用戶系統&8] &c你所填寫的舊電郵地址並不正確。' - invalid: '&8[&6用戶系統&8] &c你所填寫的電郵地址並不正確。' - added: '&8[&6用戶系統&8] &a已新增你的電郵地址。' - add_not_allowed: '&8[&6用戶系統&8] &c你不能新增電郵地址到你的帳戶。' - request_confirmation: '&8[&6用戶系統&8] &5請重覆輸入你的電郵地址。' - changed: '&8[&6用戶系統&8] &a你的電郵地址已更改。' - change_not_allowed: '&8[&6用戶系統&8] &c你不能更改你的電郵地址。' - email_show: '&8[&6用戶系統&8] &2你所使用的電郵地址為: &f%email' - no_email_for_account: '&8[&6用戶系統&8] &2你並未有綁定電郵地址到此帳戶。' - already_used: '&8[&6用戶系統&8] &4這個電郵地址已被使用。' - incomplete_settings: '&8[&6用戶系統&8] &c電郵系統錯誤,請聯絡伺服器管理員。 &7(err: mailconfig_incomplete)' - send_failure: '&8[&6用戶系統&8] &c電郵系統錯誤,請聯絡伺服器管理員。 &7(err: smtperr)' - change_password_expired: '&8[&6用戶系統&8] &c此指令已過期,請重新辦理。' - email_cooldown_error: '&8[&6用戶系統&8] &c你最近已經辦理過重寄郵件,請等待 %time 後再嘗試吧。' - -# Password recovery by email -recovery: - forgot_password_hint: '&8[&6用戶系統&8] &b忘記密碼?請使用 /email recovery <電郵地址> 來更新密碼。' - command_usage: '&8[&6用戶系統&8] &f用法:《 /email recovery <電郵> 》' - email_sent: '&8[&6用戶系統&8] &a忘記密碼信件已寄出,請查收。' - code: - code_sent: '&8[&6用戶系統&8] &b帳戶驗證碼已發送到你的郵箱,請查收。' - incorrect: '&8[&6用戶系統&8] &c帳戶驗證碼無效。 &7(你尚餘 %count 次嘗試機會)' - tries_exceeded: '&8[&6用戶系統&8] &c此驗證碼已因多次嘗試後失效,請使用《 &f/email recovery <電郵地址>&c 》重新辦理。' - correct: '&8[&6用戶系統&8] &a帳戶驗證碼輸入正確。' - change_password: '&8[&6用戶系統&8] &c請立即使用《 &f/email setpassword <新密碼>&c 》指令,以重設你的帳戶密碼。' - -# Captcha -captcha: - usage_captcha: '&8[&6用戶系統&8] &f用法:《 /captcha %captcha_code 》' - wrong_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效,請使用 《 &f/captcha %captcha_code&c 》 再次輸入。' - valid_captcha: '&8[&6用戶系統&8] &c你所輸入的驗證碼無效 !' - captcha_for_registration: '&8[&6用戶系統&8] &2要完成玩家註冊程序,請先執行驗証指令:《 &f/captcha %captcha_code&2 》' - register_captcha_valid: '&8[&6用戶系統&8] &2驗證成功 !你現在可以使用指令《 &f/register&2 》進行註冊了~' - -# Verification code -verification: - code_required: '&8[&6用戶系統&8] &e這個高級魔法指令需要再一次進行電郵驗證方可使用,請查收電郵並按信件內容進行驗證。' - command_usage: '&8[&6用戶系統&8] &f用法:《 /verification <驗證碼> 》' - incorrect_code: '&8[&6用戶系統&8] &c錯誤的驗證碼,請使用指令《 &f/verification <驗證碼>&c 》再次嘗試驗證。' - success: '&8[&6用戶系統&8] &2身份驗證成功 !你現在可以在目前的登入階段執行所有等級的指令了 !' - already_verified: '&8[&6用戶系統&8] &2你已經爲目前的登入階段成功通過電郵身份驗證了,毋須再次驗證。' - code_expired: '&8[&6用戶系統&8] &c你的驗證碼已經過期,請執行另一個高等魔法指令以觸發新的身份驗證挑戰。' - email_needed: '&8[&6用戶系統&8] &c嗯... 你的帳戶沒有已經連結的電郵地址,不能使用電郵驗證功能。' - -# Time units -time: - second: '秒' - seconds: '秒' - minute: '分' - minutes: '分' - hour: '小時' - hours: '小時' - day: '日' - days: '日' - -# Two-factor authentication -two_factor: - code_created: '&8[&6用戶系統&8] &b你的登入金鑰為&9〔 &c%code&9 〕&b,掃描連結為:%nl%&c %url' - confirmation_required: '&8[&6用戶系統&8] &b請使用指令《 &f/2fa confirm <驗證碼>&b 》以確認你的身份。' - code_required: '&8[&6用戶系統&8] &b請使用指令《 &f/2fa code <驗證碼>&b 》以驗證你的帳戶。' - already_enabled: '&8[&6用戶系統&8] &2嗯...這個帳戶已經啓用了兩步驗證功能,毋須再次啓用。' - enable_error_no_code: '&8[&6用戶系統&8] &c無效的登入金鑰 ! &f你可以使用指令《 /2fa add 》再次嘗試啓用此功能。' - enable_success: '&8[&6用戶系統&8] &2你已成功啓用兩步驗證功能 !' - enable_error_wrong_code: '&8[&6用戶系統&8] &c無效的兩步驗證碼 ! &f你可以使用指令《 /2fa add 》再次嘗試啓用此功能。' - not_enabled_error: '&8[&6用戶系統&8] &c你的帳戶尚未啓用兩步驗證功能 ! &f你可以使用指令《 /2fa add 》以啓用此功能。' - removed_success: '&8[&6用戶系統&8] &2你已成功關閉兩步驗證功能;&c為保障帳戶安全,請儘快於可行的情況下重新啟用本功能。' - invalid_code: '&8[&6用戶系統&8] &c無效的兩步驗證碼 !' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: "&8[&6用戶系統&8] &a基岩版自動登錄完成" - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&8[&6用戶系統&8] &a你在登錄時卡在了地獄門, 現已修正' - fix_underground: '&8[&6用戶系統&8] &a你被埋住了, 坐標已修正, 下次下線之前請小心!' - cannot_fix_underground: '&8[&6用戶系統&8] &a你被埋住了, 坐標無法修正, 只好送你去了最高點, 自求多福吧少年~' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&8[&6用戶系統&8] &a已修復幽靈玩家, 請重新進入' diff --git a/src/main/resources/messages/messages_zhmc.yml b/src/main/resources/messages/messages_zhmc.yml deleted file mode 100644 index a0613cb5..00000000 --- a/src/main/resources/messages/messages_zhmc.yml +++ /dev/null @@ -1,173 +0,0 @@ -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&c遊戲內註冊已停用!' - name_taken: '&c您已經註冊此用戶名!' - register_request: '&3[請先注冊] 請按T , 然後輸入 "/register [你的密碼] [重覆確認你的密碼]" 來注冊。' - command_usage: '&c使用方法: 輸入"/register [你的密碼] [重覆確認你的密碼]"' - reg_only: '&4只有註冊用戶才能加入服務器! 請訪問https://example.com註冊!' - success: '&2已成功註冊!' - kicked_admin_registered: '管理員剛剛註冊了您; 請重新登錄。' - -# Password errors on registration -password: - match_error: '&密碼錯誤!' - name_in_password: '&c你不能使用你的用戶名作密碼,請 choose another one...' - unsafe_password: '&c所選的你的密碼並不安全的,請選擇另一個...' - forbidden_characters: '&4您的密碼含有非法字符。允許的字符:%valid_chars' - wrong_length: '&c你的密碼太短或太長!請嘗試另一個!' - pwned_password: '&c你使用的密碼並不安全。它已經被使用了 %pwned_count 次! 請使用一個更強大的密碼...' - -# Login -login: - command_usage: '&b使用方法: 輸入"/login [你的密碼]" 來登入' - wrong_password: '&c密碼錯誤!' - success: '&2你已成功登入!' - login_request: '&c [請先登入] 請按T , 然後輸入 "/login [你的密碼]" 。' - timeout_error: '&4超過登錄超時,您已從伺服器中踢出,請重試!' - -# Errors -error: - denied_command: '&c你必須得到權限來使用此指令!' - denied_chat: '&c你必須得到權限來使用聊天功能!' - unregistered_user: '&c此用戶尚未注冊!' - not_logged_in: '&c你尚未登入!' - no_permission: '&4您沒有執行此操作的權限!' - unexpected_error: '&4發生錯誤!請聯繫伺服器管理員!' - max_registration: '&c您已超過註冊的最大數量(%reg_count/%max_acc %reg_names)!' - logged_in: '&c您已經登錄!' - kick_for_vip: '&3一名VIP玩家在服務器已滿時已加入伺服器!' - kick_unresolved_hostname: '&c發生了一個錯誤: 無法解析玩家的主機名' - tempban_max_logins: '&c由於登錄失敗次數過多,您已被暫時禁止。' - -# AntiBot -antibot: - kick_antibot: '伺服器正在啟用AntiBot保護模式! 您必須等待幾分鐘才能加入服務器。' - auto_enabled: '&4[AntiBotService] 伺服器由於連接數量龐大而啟用AntiBot!' - auto_disabled: '&2[AntiBotService] AntiBot將在%m分鐘後禁用!' - -# Unregister -unregister: - success: '&c帳戶已刪除!' - command_usage: '&c使用方法: "/unregister <你的密碼>"' - -# Other messages -misc: - account_not_activated: '&c你的帳戶未激活,請確認電郵!' - not_activated: '&c賬戶未激活,請註冊激活後再次嘗試.' - password_changed: '&2密碼已更變!' - logout: '&2已成功註銷!' - reload: '&2伺服器已正確地被重新加載配置和數據庫!' - usage_change_password: '&c使用方法: "/changepassword [舊密碼] [新密碼]"' - accounts_owned_self: '您擁有 %count 個帳戶:' - accounts_owned_other: '玩家 %name 擁有 %count 個帳戶:' - -# Session messages -session: - valid_session: '&2由於會話重新連接而登錄.' - invalid_session: '&c您的IP已更改,並且您的會話數據已過期!' - -# Error messages when joining -on_join_validation: - same_ip_online: '一位同一IP的玩家已在遊戲中!' - same_nick_online: '&4伺服器上已經在使用相同的用戶名!' - name_length: '&4你的暱稱太短或太長!' - characters_in_name: '&4您的暱稱含有非法字符。允許的字符:%valid_chars' - kick_full_server: '&4服務器已滿,請稍後再試!' - country_banned: '&4您的國家/地區已被禁止使用此伺服器!' - not_owner_error: '您不是此帳戶的所有者。 請選擇其他名稱!' - invalid_name_case: '您應該使用用戶名 %valid 而不是 %invalid 來加入。' - quick_command: '&c您發送命令的速度太快了,請重新加入伺服器等待一會後再使用命令' - -# Email -email: - add_email_request: '&3請使用命令: /email add [你的電郵地址] [重覆確認你的電郵地址] 將您的電子郵件添加到您的帳戶"' - usage_email_add: '&c使用方法: "/email add [電郵地址] [confirmEmail]"' - usage_email_change: '&c使用方法: "/email change [舊電郵地址] [新電郵地址]"' - new_email_invalid: '&c新電子郵件地址無效,請重試!' - old_email_invalid: '&c舊電子郵件地址無效,請重試!' - invalid: '&c電子郵件地址無效,請重試!' - added: '&2電子郵件地址已成功添加到您的帳戶!' - add_not_allowed: '&c伺服器不允許添加電子郵箱' - request_confirmation: '&c請確認你的電郵地址!' - changed: '&2已正確地更改電子郵件地址!' - change_not_allowed: '&c伺服器不允許修改郵箱地址' - email_show: '&a該賬戶使用的電子郵箱為: &a%email' - no_email_for_account: '&c當前並沒有任何郵箱與該賬戶綁定' - already_used: '&4此電子郵件地址已被使用' - incomplete_settings: '缺少必要的配置來為發送電子郵件。請聯繫管理員。' - send_failure: '&c郵件已被作廢,請檢查您的郵箱是否正常工作.' - change_password_expired: '&c您不能使用此命令更改密碼' - email_cooldown_error: '&c您需要等待 %time 後才能再次請求發送' - -# Password recovery by email -recovery: - forgot_password_hint: '&3忘記密碼了嗎? 請使用命令: "/email recovery [你的電郵地址]"' - command_usage: '&c使用方法: "/email recovery [電郵地址]"' - email_sent: '&2帳戶恢復電子郵件已成功發送! 請檢查您的電子郵件收件箱!' - code: - code_sent: '已將重設密碼的恢復代碼發送到您的電子郵件。' - incorrect: '恢復代碼錯誤!使用指令: "/email recovery [電郵地址]" 生成新的一個恢復代碼。' - tries_exceeded: '&a您已經達到輸入驗證碼次數的最大允許次數.' - correct: '&a*** 驗證通過 ***' - change_password: '&c請使用 /email setpassword <新密碼> 立即設置新的密碼' - -# Captcha -captcha: - usage_captcha: '&3T要登錄您必須使用captcha驗證碼,請使用命令: "/captcha %captcha_code"' - wrong_captcha: '&c驗證碼錯誤!請按T在聊天中輸入 "/captcha %captcha_code"' - valid_captcha: '&2驗證碼正確!' - captcha_for_registration: '&7請輸入 /captcha %captcha_code 來驗證操作.' - register_captcha_valid: '&a驗證通過, 現在可以使用 /register 註冊啦!' - -# Verification code -verification: - code_required: '&a*** 已發送驗證郵件 ***' - command_usage: '&c使用方法:/verification <驗證碼>' - incorrect_code: '&c錯誤的驗證碼.' - success: '&a*** 驗證通過 ***' - already_verified: '&a您已經通過驗證' - code_expired: '&c驗證碼已失效' - email_needed: '&c郵箱未綁定' - -# Time units -time: - second: '秒' - seconds: '秒' - minute: '分' - minutes: '分' - hour: '時' - hours: '時' - day: '天' - days: '天' - -# Two-factor authentication -two_factor: - code_created: '&2您的密碼是 %code。您可以從這裡掃描 %url' - confirmation_required: '&7請輸入“/totp confirm <驗證碼>”來確認啟動雙重驗證' - code_required: '&c請輸入“/totp code <驗證碼>”來提交驗證碼' - already_enabled: '&a雙重驗證已啟用' - enable_error_no_code: '&c驗證碼丟失' - enable_success: '&a已成功啟用雙重驗證' - enable_error_wrong_code: '&c驗證碼錯誤或者已經過期,請重新執行“/totp add”' - not_enabled_error: '&c雙重驗證未在您的賬號上啟用,請使用“/totp add”來啟用' - removed_success: '&c雙重驗證已從您的賬號上禁用' - invalid_code: '&c無效的驗證碼' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: "&a基岩版自動登錄完成" - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&a你在登錄時卡在了地獄門, 現已修正' - fix_underground: '&a你被埋住了, 坐標已修正, 下次下線之前請小心!' - cannot_fix_underground: '&a你被埋住了, 坐標無法修正, 只好送你去了最高點, 自求多福吧少年~' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&a已修復幽靈玩家, 請重新進入' diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml deleted file mode 100644 index a1eb1e07..00000000 --- a/src/main/resources/messages/messages_zhtw.yml +++ /dev/null @@ -1,175 +0,0 @@ -# Translators: MineWolf50, lifehome, haer0248 # -# -------------------------------------------- # -# List of global tags: -# %nl% - Goes to new line. -# %username% - Replaces the username of the player receiving the message. -# %displayname% - Replaces the nickname (and colors) of the player receiving the message. - -# Registration -registration: - disabled: '&b【AuthMe】&6已關閉註冊功能。' - name_taken: '&b【AuthMe】&6這個帳號已經被註冊過了!' - register_request: '&b【AuthMe】&6請使用 "&c/register <密碼> <確認密碼>" 來註冊。' - command_usage: '&b【AuthMe】&6用法: &c"/register <密碼> <確認密碼>"' - reg_only: '&b【AuthMe】&6請到下列網站:「 https://example.tw 」進行註冊。' - success: '&b【AuthMe】&6您已成功註冊!' - kicked_admin_registered: '&b【AuthMe】&6管理員已協助您註冊,請重新登入。' - -# Password errors on registration -password: - match_error: '&b【AuthMe】&6兩次輸入的密碼不一致!' - name_in_password: '&b【AuthMe】&6您不可以用您的 ID (遊戲名稱) 來當作密碼!' - unsafe_password: '&b【AuthMe】&6您不可以使用這個不安全的密碼!' - forbidden_characters: '&b【AuthMe】&c密碼包含非法字符,可使用:%valid_chars' - wrong_length: '&b【AuthMe】&6您的密碼 超過最大字數 / 小於最小字數' - pwned_password: '&b【AuthMe】&c你使用的密碼並不安全。它已經被使用了 %pwned_count 次! 請使用一個更強大的密碼...' - -# Login -login: - command_usage: '&b【AuthMe】&6用法: &c"/login <密碼>"' - wrong_password: '&b【AuthMe】&6密碼錯誤!' - success: '&b【AuthMe】&6密碼正確,您已成功登入!' - login_request: '&b【AuthMe】&6請使用 &c"/login <密碼>" &6來登入。' - timeout_error: '&b【AuthMe】&6超過登入時間,請稍後再試一次。' - -# Errors -error: - denied_command: '&b【AuthMe】&c使用指令之前必須通過驗證!' - denied_chat: '&b【AuthMe】&c說話之前必須通過驗證!' - unregistered_user: '&b【AuthMe】&6這個帳號還沒有註冊過。' - not_logged_in: '&b【AuthMe】&6您還沒有登入!' - no_permission: '&b【AuthMe】&6您沒有使用該指令的權限。' - unexpected_error: '&b【AuthMe】&6發生錯誤,請聯繫管理員' - max_registration: '&b【AuthMe】&6您的 IP 位置所註冊的帳號數量已經達到最大限制。' - logged_in: '&b【AuthMe】&6您已經登入了!' - kick_for_vip: '&b【AuthMe】&6您已經被請出。&c原因:有 VIP 玩家登入伺服器' - kick_unresolved_hostname: '&b【AuthMe】&6無法解析玩家主機名稱。' - tempban_max_logins: '&b【AuthMe】&c您已被暫時封鎖IP位置,因為您登入失敗太多次。' - -# AntiBot -antibot: - kick_antibot: '&b【AuthMe】&cAntiBotMod 正在啟用中,請稍後再嘗試登入吧!' - auto_enabled: '&b【AuthMe】&6AntiBotMod 已自動啟用!' - auto_disabled: '&b【AuthMe】&6AntiBotMod 將於 &c%m &6分鐘後自動關閉' - -# Unregister -unregister: - success: '&b【AuthMe】&6您已經成功註銷。' - command_usage: '&b【AuthMe】&6用法:&c"/unregister <密碼>"' - -# Other messages -misc: - account_not_activated: '&b【AuthMe】&6您的帳號還沒有經過驗證!檢查看看您的電子郵件 (Email) 吧!' - not_activated: '&b【AuthMe】&c賬戶未激活,請註冊激活後再次嘗試.' - password_changed: '&b【AuthMe】&6密碼變更成功!' - logout: '&b【AuthMe】&6您已成功登出。' - reload: '&b【AuthMe】&6已重新讀取設定檔及資料庫。' - usage_change_password: '&b【AuthMe】&6用法:&c"/changepassword <舊密碼> <新密碼>"' - accounts_owned_self: '&b【AuthMe】&6您擁有 %count 個帳號:' - accounts_owned_other: '&b【AuthMe】&6玩家 %name 擁有 %count 個帳號:' - -# Session messages -session: - valid_session: '&b【AuthMe】&6您已經成功登入!' - invalid_session: '&b【AuthMe】&6Session驗證不相符!' - -# Error messages when joining -on_join_validation: - same_ip_online: '&b【AuthMe】&6相同IP玩家在線上!' - same_nick_online: '&b【AuthMe】&6有同樣帳號的玩家在線上!' - name_length: '&b【AuthMe】&6您的暱稱 太長 / 太短 了!' - characters_in_name: '&b【AuthMe】&6暱稱裡能使用的字符為: %valid_chars' - kick_full_server: '&b【AuthMe】&6伺服器已經滿了,請等等再試一次。' - country_banned: '&b【AuthMe】&6您所在的地區無法進入此伺服器。' - not_owner_error: '&b【AuthMe】&4警告!&c您並不是此帳戶持有人,請立即登出。' - invalid_name_case: '&b【AuthMe】&4警告!&c您應該使用「%valid」而並非「%invalid」登入遊戲。' - quick_command: '&b【AuthMe】&4指令使用過快,請加入伺服器後稍等一下再使用指令。' - -# Email -email: - add_email_request: '&b【AuthMe】&6請使用 &c"/email add <電子郵件> <再次輸入電子郵件>" &6來新增電子郵件' - usage_email_add: '&b【AuthMe】&6用法: &c"/email add <電子郵件> <再次輸入電子郵件>"' - usage_email_change: '&b【AuthMe】&6用法: &c"/email change <舊的電子郵件> <新的電子郵件>"' - new_email_invalid: '&b【AuthMe】&6新的電子郵件無效!' - old_email_invalid: '&b【AuthMe】&6舊的電子郵件無效!' - invalid: '&b【AuthMe】&6無效的電子郵件!' - added: '&b【AuthMe】&6已新增電子郵件!' - add_not_allowed: '&b【AuthMe】&c不允許新增電子郵件' - request_confirmation: '&b【AuthMe】&6請驗證您的電子郵件!' - changed: '&b【AuthMe】&6電子郵件已變更!' - change_not_allowed: '&b【AuthMe】&c不允許變更電子郵件' - email_show: '&b【AuthMe】&2目前的電子郵件:&f%email' - no_email_for_account: '&b【AuthMe】&2您目前沒有設定電子郵件。' - already_used: '&b【AuthMe】&4這個電子郵件已被使用。' - incomplete_settings: '&b【AuthMe】&4因為電子郵件設定不完整導致無法傳送,請聯絡管理員。' - send_failure: '&b【AuthMe】&4無法傳送電子郵件,請聯絡管理員。' - change_password_expired: '&b【AuthMe】&6您現在不能使用這個指令變更密碼了。' - email_cooldown_error: '&b【AuthMe】&c電子郵件已經寄出了,您只能在 %time 後才能傳送。' - -# Password recovery by email -recovery: - forgot_password_hint: '&b【AuthMe】&6忘記密碼了嗎?使用 &c"/email recovery <電子郵件>"' - command_usage: '&b【AuthMe】&6用法: &c"/email recovery <電子郵件>"' - email_sent: '&b【AuthMe】&6已經送出重設密碼要求至您的電子郵件,請查收。' - code: - code_sent: '&b【AuthMe】&6忘記密碼的恢復密碼電子郵件已傳送至您的信箱中。' - incorrect: '&b【AuthMe】&6恢復密碼錯誤!您剩餘 %count 次嘗試機會。' - tries_exceeded: '&b【AuthMe】&6恢復密碼過多次數錯誤。使用 "/email recovery [電子郵件]" 取得新的恢復密碼。' - correct: '&b【AuthMe】&6恢復密碼正確!' - change_password: '&b【AuthMe】&6請使用 "/email setpassword <新密碼>" 變更您的密碼。' - -# Captcha -captcha: - usage_captcha: '&b【AuthMe】&6請用 &c"/captcha %captcha_code" &6來輸入您的驗證碼。' - wrong_captcha: '&b【AuthMe】&6錯誤的驗證碼,請使用 "/captcha %captcha_code" 再試一次。' - valid_captcha: '&b【AuthMe】&6驗證碼無效。' - captcha_for_registration: '&b【AuthMe】&6註冊前必須先提供驗證碼,使用 /captcha %captcha_code 來驗證。' - register_captcha_valid: '&b【AuthMe】&2驗證已通過,現在可以使用 /register 來進行註冊了。' - -# Verification code -verification: - code_required: '&b【AuthMe】&3敏感指令,需要電子郵件驗證後才能執行,請檢查電子郵件。' - command_usage: '&b【AuthMe】&c用法:/verification <驗證碼>' - incorrect_code: '&b【AuthMe】&c驗證碼錯誤,請在聊天室使用 "/verification <驗證碼>" 電子郵件收到的驗證碼' - success: '&b【AuthMe】&2身分已驗證,您現在可以使用所有指令!' - already_verified: '&b【AuthMe】&2您已經可以使用所有指令!' - code_expired: '&b【AuthMe】&3驗證碼已過期,請使用其他敏感指令來取得新的驗證碼!' - email_needed: '&b【AuthMe】&3若需要身分驗證,請先新增電子郵件!' - -# Time units -time: - second: '秒' - seconds: '秒' - minute: '分' - minutes: '分' - hour: '時' - hours: '時' - day: '天' - days: '天' - -# Two-factor authentication -two_factor: - code_created: '&b【AuthMe】&b您的登入金鑰為&9「%c%code&9」&b,掃描連結為:&c %url' - confirmation_required: '&b【AuthMe】&6請使用 /2fa confirm <驗證碼> 來確認雙重驗證。' - code_required: '&b【AuthMe】&c請使用 /2fa code <驗證碼> 來完成驗證。' - already_enabled: '&b【AuthMe】&c雙重驗證已經開啟。' - enable_error_no_code: '&b【AuthMe】&6雙重驗證代碼不存在或失效,使用 /2fa add 來新增。' - enable_success: '&b【AuthMe】&6雙重驗證已開啟!' - enable_error_wrong_code: '&b【AuthMe】&6雙重驗證代碼錯誤或失效,使用 /2fa add 來新增。' - not_enabled_error: '&b【AuthMe】&6雙重驗證尚未開啟,使用 /2fa add 來開啟。' - removed_success: '&b【AuthMe】&6雙重驗證已成功移除!' - invalid_code: '&b【AuthMe】&c驗證碼錯誤。' - -# 3rd party features: Bedrock Auto Login -bedrock_auto_login: - success: "&b【AuthMe】&a基岩版自動登錄完成" - -# 3rd party features: Login Location Fix -login_location_fix: - fix_portal: '&b【AuthMe】&a你在登錄時卡在了地獄門, 現已修正' - fix_underground: '&b【AuthMe】&a你被埋住了, 坐標已修正, 下次下線之前請小心!' - cannot_fix_underground: '&b【AuthMe】&a你被埋住了, 坐標無法修正, 只好送你去了最高點, 自求多福吧少年~' - -# 3rd party features: Double Login Fix -double_login_fix: - fix_message: '&b【AuthMe】&a已修復幽靈玩家, 請重新進入' diff --git a/src/main/resources/new_email.html b/src/main/resources/new_email.html deleted file mode 100644 index 74a1a087..00000000 --- a/src/main/resources/new_email.html +++ /dev/null @@ -1,127 +0,0 @@ -
- -
- - - - - - -
- - - - - - - - - - - - -
-

账户激活邮件

-
- - - - - - -
-

Minecraft ·

-
- - - - - - - - - - - - - - - - - - -
- 您的账户初始密码为 -
-
-
已将地址()进行记录. -
-
请妥善保存,在新地址上进行登录时,需提供该密码. -
若非必要,请勿更换密码,否则将对您的账户安全构成威胁. -
账户所绑定的邮箱地址已被永久存储,需要更换请联系管理员. -
-
更换密码: /changepassword [新密码] -
-
-
账户将在激活后生效 -
欢迎您的加入~! -
- -
-
-
-
- - - - - - -
-

© 2024 HomoCraft. All rights reserved.

- wdsj.in -
-
-
-
-
diff --git a/src/main/resources/otheraccounts.yml b/src/main/resources/otheraccounts.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/resources/players.yml b/src/main/resources/players.yml deleted file mode 100644 index cf746f52..00000000 --- a/src/main/resources/players.yml +++ /dev/null @@ -1 +0,0 @@ -players: [] \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml deleted file mode 100644 index 6414af78..00000000 --- a/src/main/resources/plugin.yml +++ /dev/null @@ -1,316 +0,0 @@ -name: AuthMe -authors: [sgdc3, games647, Hex3l, krusic22, DGun Otto] -website: https://github.com/HaHaWTH/AuthMeReReloaded/ -description: A fork of AuthMeReloaded that contains bug fixes -main: fr.xephi.authme.AuthMe -folia-supported: true -version: 5.6.0-FORK-b50 -api-version: 1.13 -softdepend: - - Vault - - LuckPerms - - PermissionsEx - - bPermissions - - zPermissions - - Multiverse-Core - - Essentials - - EssentialsSpawn - - ProtocolLib - - floodgate -commands: - authme: - description: AuthMe op commands - usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|totp|disabletotp|spawn|setspawn|firstspawn|setfirstspawn|purge|purgeplayer|backup|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages|recent|debug - email: - description: Add email or recover password - usage: /email show|add|change|recover|code|setpassword - login: - description: Login command - usage: /login - aliases: - - l - logout: - description: Logout command - usage: /logout - register: - description: Register an account - usage: /register [password] [verifyPassword] - aliases: - - reg - unregister: - description: Unregister an account - usage: /unregister - aliases: - - unreg - changepassword: - description: Change password of an account - usage: /changepassword - aliases: - - changepass - - cp - totp: - description: TOTP commands - usage: /totp code|add|confirm|remove - aliases: - - 2fa - captcha: - description: Captcha command - usage: /captcha - verification: - description: Verification command - usage: /verification -permissions: - authme.admin.*: - description: Gives access to all admin commands - children: - authme.admin.accounts: true - authme.admin.antibotmessages: true - authme.admin.backup: true - authme.admin.changemail: true - authme.admin.changepassword: true - authme.admin.converter: true - authme.admin.firstspawn: true - authme.admin.forcelogin: true - authme.admin.getemail: true - authme.admin.getip: true - authme.admin.lastlogin: true - authme.admin.purge: true - authme.admin.purgebannedplayers: true - authme.admin.purgelastpos: true - authme.admin.purgeplayer: true - authme.admin.register: true - authme.admin.reload: true - authme.admin.seeotheraccounts: true - authme.admin.seerecent: true - authme.admin.setfirstspawn: true - authme.admin.setspawn: true - authme.admin.spawn: true - authme.admin.switchantibot: true - authme.admin.totpdisable: true - authme.admin.totpviewstatus: true - authme.admin.unregister: true - authme.admin.updatemessages: true - authme.admin.accounts: - description: Administrator command to see all accounts associated with a user. - default: op - authme.admin.antibotmessages: - description: Permission to see Antibot messages. - default: op - authme.admin.backup: - description: Allows to use the backup command. - default: op - authme.admin.changemail: - description: Administrator command to set or change the email address of a user. - default: op - authme.admin.changepassword: - description: Administrator command to change the password of a user. - default: op - authme.admin.converter: - description: Administrator command to convert old or other data to AuthMe data. - default: op - authme.admin.firstspawn: - description: Administrator command to teleport to the first AuthMe spawn. - default: op - authme.admin.forcelogin: - description: Administrator command to force-login an existing user. - default: op - authme.admin.getemail: - description: Administrator command to get the email address of a user, if set. - default: op - authme.admin.getip: - description: Administrator command to get the last known IP of a user. - default: op - authme.admin.lastlogin: - description: Administrator command to see the last login date and time of a user. - default: op - authme.admin.purge: - description: Administrator command to purge old user data. - default: op - authme.admin.purgebannedplayers: - description: Administrator command to purge all data associated with banned players. - default: op - authme.admin.purgelastpos: - description: Administrator command to purge the last position of a user. - default: op - authme.admin.purgeplayer: - description: Administrator command to purge a given player. - default: op - authme.admin.register: - description: Administrator command to register a new user. - default: op - authme.admin.reload: - description: Administrator command to reload the plugin configuration. - default: op - authme.admin.seeotheraccounts: - description: Permission to see the other accounts of the players that log in. - default: op - authme.admin.seerecent: - description: Administrator command to see the last recently logged in players. - default: op - authme.admin.setfirstspawn: - description: Administrator command to set the first AuthMe spawn. - default: op - authme.admin.setspawn: - description: Administrator command to set the AuthMe spawn. - default: op - authme.admin.spawn: - description: Administrator command to teleport to the AuthMe spawn. - default: op - authme.admin.switchantibot: - description: Administrator command to toggle the AntiBot protection status. - default: op - authme.admin.totpdisable: - description: Administrator command to disable the two-factor auth of a user. - default: op - authme.admin.totpviewstatus: - description: Administrator command to see whether a player has enabled two-factor - authentication. - default: op - authme.admin.unregister: - description: Administrator command to unregister an existing user. - default: op - authme.admin.updatemessages: - description: Permission to use the update messages command. - default: op - authme.allowchatbeforelogin: - description: Permission to send chat messages before being logged in. - default: false - authme.allowmultipleaccounts: - description: Permission to be able to register multiple accounts. - default: op - authme.bypassbungeesend: - description: Permission node to bypass BungeeCord server teleportation. - default: false - authme.bypassantibot: - description: Permission node to bypass AntiBot protection. - default: op - authme.bypasscountrycheck: - description: Permission to bypass the GeoIp country code check. - default: false - authme.bypassforcesurvival: - description: Permission for users to bypass force-survival mode. - default: op - authme.bypasspurge: - description: Permission to bypass the purging process. - default: false - authme.debug: - description: Gives access to /authme debug and all its sections - children: - authme.debug.command: true - authme.debug.country: true - authme.debug.db: true - authme.debug.group: true - authme.debug.limbo: true - authme.debug.mail: true - authme.debug.mysqldef: true - authme.debug.perm: true - authme.debug.spawn: true - authme.debug.stats: true - authme.debug.valid: true - authme.debug.command: - description: General permission to use the /authme debug command. - default: op - authme.debug.country: - description: Permission to use the country lookup section. - default: op - authme.debug.db: - description: Permission to view data from the database. - default: op - authme.debug.group: - description: Permission to view permission groups. - default: op - authme.debug.limbo: - description: Permission to use the limbo data viewer. - default: op - authme.debug.mail: - description: Permission to use the test email sender. - default: op - authme.debug.mysqldef: - description: Permission to change nullable status of MySQL columns. - default: op - authme.debug.perm: - description: Permission to use the permission checker. - default: op - authme.debug.spawn: - description: Permission to view spawn information. - default: op - authme.debug.stats: - description: Permission to use the stats section. - default: op - authme.debug.valid: - description: Permission to use sample validation. - default: op - authme.player.*: - description: Gives access to all player commands - children: - authme.player.canbeforced: true - authme.player.captcha: true - authme.player.changepassword: true - authme.player.email.add: true - authme.player.email.recover: true - authme.player.email.see: true - authme.player.login: true - authme.player.logout: true - authme.player.protection.quickcommandsprotection: true - authme.player.register: true - authme.player.security.verificationcode: true - authme.player.totpadd: true - authme.player.totpremove: true - authme.player.canbeforced: - description: Permission for users a login can be forced to. - default: true - authme.player.captcha: - description: Command permission to use captcha. - default: true - authme.player.changepassword: - description: Command permission to change the password. - default: true - authme.player.email: - description: Gives access to all email commands - children: - authme.player.email.add: true - authme.player.email.recover: true - authme.player.email.see: true - authme.player.email.add: - description: Command permission to add an email address. - default: true - authme.player.email.change: - description: Command permission to change the email address. - default: op - authme.player.email.recover: - description: Command permission to recover an account using its email address. - default: true - authme.player.email.see: - description: Command permission to see the own email address. - default: true - authme.player.login: - description: Command permission to login. - default: true - authme.player.logout: - description: Command permission to logout. - default: true - authme.player.protection.quickcommandsprotection: - description: Permission that enables on join quick commands checks for the player. - default: true - authme.player.register: - description: Command permission to register. - default: true - authme.player.security.verificationcode: - description: Permission to use the email verification codes feature. - default: true - authme.player.seeownaccounts: - description: Permission to use to see own other accounts. - default: true - authme.player.totpadd: - description: Permission to enable two-factor authentication. - default: true - authme.player.totpremove: - description: Permission to disable two-factor authentication. - default: true - authme.player.unregister: - description: Command permission to unregister. - default: op - authme.vip: - description: When the server is full and someone with this permission joins the - server, someone will be kicked. - default: false diff --git a/src/main/resources/recovery_code_email.html b/src/main/resources/recovery_code_email.html deleted file mode 100644 index c41c00c9..00000000 --- a/src/main/resources/recovery_code_email.html +++ /dev/null @@ -1,120 +0,0 @@ -
- -
- - - - - - -
- - - - - - - - - - - - -
-

代码验证邮件

-
- - - - - - -
-

Minecraft ·

-
- - - - - - - - - - - - - - - - - - -
- 您正在申请的验证码为 -
-
-
使用指令: /email code 来完成验证过程. -
-
-
验证码将在小时后失效 -
- -
-
-
-
- - - - - - -
-

© 2024 HomoCraft. All rights reserved.

- wdsj.in -
-
-
-
-
diff --git a/src/main/resources/shutdown.html b/src/main/resources/shutdown.html deleted file mode 100644 index 2819ebfc..00000000 --- a/src/main/resources/shutdown.html +++ /dev/null @@ -1,118 +0,0 @@ -
- -
- - - - - - -
- - - - - - - - - - - - -
-

服务器关闭通知

-
- - - - - - -
-

Minecraft ·

-
- - - - - - - - - - - - - - - -
-
紧急通知
-
服务器当前已被关闭 -
-
请及时检查服务器运行状态. -
-
-
-
IrisCraft Team -
- -
-
-
-
- - - - - - -
-

© 2024 HomoCraft. All rights reserved.

- wdsj.in -
-
-
-
-
diff --git a/src/main/resources/spawn.yml b/src/main/resources/spawn.yml deleted file mode 100644 index 5191803c..00000000 --- a/src/main/resources/spawn.yml +++ /dev/null @@ -1,14 +0,0 @@ -spawn: - world: '' - x: '' - y: '' - z: '' - yaw: '' - pitch: '' -firstspawn: - world: '' - x: '' - y: '' - z: '' - yaw: '' - pitch: '' \ No newline at end of file diff --git a/src/main/resources/verification_code_email.html b/src/main/resources/verification_code_email.html deleted file mode 100644 index 0e8d1ddd..00000000 --- a/src/main/resources/verification_code_email.html +++ /dev/null @@ -1,120 +0,0 @@ -
- -
- - - - - - -
- - - - - - - - - - - - -
-

代码验证邮件

-
- - - - - - -
-

Minecraft ·

-
- - - - - - - - - - - - - - - - - - -
- 您正在申请的验证码为 -
-
-
使用指令: /verification 来完成验证过程. -
-
-
验证码将在30分钟后失效 -
- -
-
-
-
- - - - - - -
-

© 2024 HomoCraft. All rights reserved.

- wdsj.in -
-
-
-
-