package fr.xephi.authme; import ch.jalu.injector.Injector; import ch.jalu.injector.InjectorBuilder; 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.GuiCaptchaHandler; 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.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.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.bukkit.scheduler.BukkitScheduler; import org.jetbrains.annotations.NotNull; import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Objects; import java.util.Scanner; import java.util.function.Consumer; import java.util.logging.Level; 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.6.0-Fork"; private static final String pluginBuild = "b"; private static String pluginBuildNumber = "44"; // 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; } /** * 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); // 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(); Objects.requireNonNull(getCommand("register")).setTabCompleter(new TabCompleteHandler()); Objects.requireNonNull(getCommand("login")).setTabCompleter(new TabCompleteHandler()); logger.info("AuthMeReReloaded is enabled successfully!"); // Purge on start if enabled PurgeService purgeService = injector.getSingleton(PurgeService.class); purgeService.runAutoPurge(); // 注册玩家加入事件监听 // register3rdPartyListeners(); logger.info("GitHub: https://github.com/HaHaWTH/AuthMeReReloaded/"); if (settings.getProperty(SecuritySettings.CHECK_FOR_UPDATES)) { checkForUpdates(); } } //Migrated /** * 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.register(BukkitScheduler.class, getServer().getScheduler()); 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); // 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.GUI_CAPTCHA) && getServer().getPluginManager().getPlugin("ProtocolLib") != null) { pluginManager.registerEvents(injector.getSingleton(GuiCaptchaHandler.class), this); logger.info("(Beta)GUICaptcha is enabled successfully!"); logger.info("These features are still in early development, if you encountered any problem, please report."); } else if (settings.getProperty(SecuritySettings.GUI_CAPTCHA) && getServer().getPluginManager().getPlugin("ProtocolLib") == null) { logger.warning("ProtocolLib is not loaded, can't enable GUI Captcha."); } 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.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 static final String owner = "HaHaWTH"; // private static final String owner_gitee = "Shixuehan114514"; private static final String repo = "AuthMeReReloaded"; private void checkForUpdates() { logger.info("Checking for updates..."); bukkitService.runTaskAsynchronously(() -> { try { // 从南通集线器获取最新版本号 URL url = new URL("https://api.github.com/repos/" + owner + "/" + repo + "/releases/latest"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); // 设置连接超时为10秒 conn.setReadTimeout(10000); // 设置读取超时为10秒 Scanner scanner = new Scanner(conn.getInputStream()); String response = scanner.useDelimiter("\\Z").next(); scanner.close(); // 处理JSON响应 String latestVersion = response.substring(response.indexOf("tag_name") + 11); latestVersion = latestVersion.substring(0, latestVersion.indexOf("\"")); if (isUpdateAvailable(latestVersion)) { String message = "New version available! Latest:" + latestVersion + " Current:" + pluginBuild + pluginBuildNumber; getLogger().log(Level.WARNING, message); getLogger().log(Level.WARNING, "Download from here: https://github.com/HaHaWTH/AuthMeReReloaded/releases/latest"); } else { getLogger().log(Level.INFO, "You are running the latest version."); } } catch (IOException ignored) { } }); } private boolean isUpdateAvailable(String latestVersion) { // Extract the first character and the remaining digits from the version string char latestChar = latestVersion.charAt(0); int latestNumber = Integer.parseInt(latestVersion.substring(1)); char currentChar = pluginBuild.charAt(0); int currentNumber = Integer.parseInt(pluginBuildNumber); // Compare the characters first if (latestChar > currentChar) { return true; } else if (latestChar < currentChar) { return false; } else { // If the characters are the same, compare the numbers return latestNumber > currentNumber; } } private void checkServerType() { 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 "-"; } } }