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 index 037846aaf..5a3604f1d 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java @@ -11,10 +11,10 @@ import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.settings.Settings; 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.Collection; import java.util.List; /** @@ -44,8 +44,7 @@ public class ReloadCommand implements ExecutableCommand { ConsoleLogger.setLoggingOptions(settings); // We do not change database type for consistency issues, but we'll output a note in the logs if (!settings.getProperty(DatabaseSettings.BACKEND).equals(dataSource.getType())) { - ConsoleLogger.info("Note: cannot change database type during /authme reload"); - sender.sendMessage("Note: cannot change database type during /authme reload"); + Utils.logAndSendMessage(sender, "Note: cannot change database type during /authme reload"); } performReloadOnServices(); commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); @@ -57,14 +56,10 @@ public class ReloadCommand implements ExecutableCommand { } private void performReloadOnServices() { - Collection reloadables = injector.retrieveAllOfType(Reloadable.class); - for (Reloadable reloadable : reloadables) { - reloadable.reload(); - } + injector.retrieveAllOfType(Reloadable.class) + .forEach(r -> r.reload()); - Collection settingsDependents = injector.retrieveAllOfType(SettingsDependent.class); - for (SettingsDependent dependent : settingsDependents) { - dependent.reload(settings); - } + injector.retrieveAllOfType(SettingsDependent.class) + .forEach(s -> s.reload(settings)); } } 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 new file mode 100644 index 000000000..05de8ab13 --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/CountryLookup.java @@ -0,0 +1,77 @@ +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.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) { + 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); + } + } + + 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"); + } + + private void outputInfoForPlayer(CommandSender sender, String name) { + PlayerAuth auth = dataSource.getAuth(name); + if (auth == null) { + sender.sendMessage("No player with name '" + name + "'"); + } else { + sender.sendMessage("Player '" + name + "' has IP address " + auth.getIp()); + outputInfoForIpAddr(sender, auth.getIp()); + } + } +} 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 index ec4cfd830..ae3dc22f1 100644 --- 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 @@ -19,8 +19,9 @@ public class DebugCommand implements ExecutableCommand { @Inject private Factory debugSectionFactory; - private Set> sectionClasses = - ImmutableSet.of(PermissionGroups.class, TestEmailSender.class, PlayerAuthViewer.class, LimboPlayerViewer.class); + private Set> sectionClasses = ImmutableSet.of( + PermissionGroups.class, TestEmailSender.class, PlayerAuthViewer.class, LimboPlayerViewer.class, + CountryLookup.class); private Map sections; diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index f62b00e15..2ca1df559 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -45,7 +45,10 @@ public class MySQL implements DataSource { private HikariDataSource ds; private String phpBbPrefix; + private String IPBPrefix; private int phpBbGroup; + private int IPBGroup; + private int XFGroup; private String wordpressPrefix; public MySQL(Settings settings) throws ClassNotFoundException, SQLException { @@ -96,6 +99,9 @@ public class MySQL implements DataSource { this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); + this.IPBPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX); + this.IPBGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID); + this.XFGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID); this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); if (poolSize == -1) { @@ -334,8 +340,39 @@ public class MySQL implements DataSource { pst.close(); } } - - if (hashAlgorithm == HashAlgorithm.PHPBB) { + if (hashAlgorithm == HashAlgorithm.IPB4){ + sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; + pst = con.prepareStatement(sql); + pst.setString(1, auth.getNickname()); + rs = pst.executeQuery(); + if (rs.next()){ + // Update player group in core_members + sql = "UPDATE " + IPBPrefix + tableName + " SET "+ tableName + ".member_group_id=? WHERE " + col.NAME + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setInt(1, IPBGroup); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + pst2.close(); + // Get current time without ms + long time = System.currentTimeMillis() / 1000; + // update joined date + sql = "UPDATE " + IPBPrefix + tableName + " SET "+ tableName + ".joined=? WHERE " + col.NAME + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setLong(1, time); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + pst2.close(); + // Update last_visit + sql = "UPDATE " + IPBPrefix + tableName + " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setLong(1, time); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + pst2.close(); + } + rs.close(); + pst.close(); + } else if (hashAlgorithm == HashAlgorithm.PHPBB) { sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; pst = con.prepareStatement(sql); pst.setString(1, auth.getNickname()); @@ -477,8 +514,9 @@ public class MySQL implements DataSource { pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;"); pst.setString(1, auth.getNickname()); rs = pst.executeQuery(); - if (rs.next()) { + if (rs.next()) { int id = rs.getInt(col.ID); + // Insert player password, salt in xf_user_authenticate sql = "INSERT INTO xf_user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)"; pst2 = con.prepareStatement(sql); pst2.setInt(1, id); @@ -490,6 +528,39 @@ public class MySQL implements DataSource { pst2.setBlob(3, blob); pst2.executeUpdate(); pst2.close(); + // Update player group in xf_users + sql = "UPDATE " + tableName + " SET "+ tableName + ".user_group_id=? WHERE " + col.NAME + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setInt(1, XFGroup); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + pst2.close(); + // Update player permission combination in xf_users + sql = "UPDATE " + tableName + " SET "+ tableName + ".permission_combination_id=? WHERE " + col.NAME + "=?;"; + pst2 = con.prepareStatement(sql); + pst2.setInt(1, XFGroup); + pst2.setString(2, auth.getNickname()); + pst2.executeUpdate(); + pst2.close(); + // Insert player privacy combination in xf_user_privacy + sql = "INSERT INTO xf_user_privacy (user_id, allow_view_profile, allow_post_profile, allow_send_personal_conversation, allow_view_identities, allow_receive_news_feed) VALUES (?,?,?,?,?,?)"; + pst2 = con.prepareStatement(sql); + pst2.setInt(1, id); + pst2.setString(2, "everyone"); + pst2.setString(3, "members"); + pst2.setString(4, "members"); + pst2.setString(5, "everyone"); + pst2.setString(6, "everyone"); + pst2.executeUpdate(); + pst2.close(); + // Insert player group relation in xf_user_group_relation + sql = "INSERT INTO xf_user_group_relation (user_id, user_group_id, is_primary) VALUES (?,?,?)"; + pst2 = con.prepareStatement(sql); + pst2.setInt(1, id); + pst2.setInt(2, XFGroup); + pst2.setString(3, "1"); + pst2.executeUpdate(); + pst2.close(); } rs.close(); pst.close(); diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index 344c39c96..ece409005 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -1,8 +1,10 @@ package fr.xephi.authme.mail; import fr.xephi.authme.ConsoleLogger; +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; @@ -56,6 +58,9 @@ public class SendMailSSL { 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; diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 7ae0b3a87..b246bf594 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -11,7 +11,6 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.permission.AdminPermission; -import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.AsynchronousProcess; @@ -44,9 +43,6 @@ public class AsynchronousLogin implements AsynchronousProcess { @Inject private CommonService service; - @Inject - private PermissionsManager permissionsManager; - @Inject private PlayerCache playerCache; @@ -290,10 +286,10 @@ public class AsynchronousLogin implements AsynchronousProcess { for (Player onlinePlayer : bukkitService.getOnlinePlayers()) { if (onlinePlayer.getName().equalsIgnoreCase(player.getName()) - && permissionsManager.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) { + && service.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) { service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_SELF, Integer.toString(auths.size())); onlinePlayer.sendMessage(message); - } else if (permissionsManager.hasPermission(onlinePlayer, AdminPermission.SEE_OTHER_ACCOUNTS)) { + } 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); @@ -313,7 +309,7 @@ public class AsynchronousLogin implements AsynchronousProcess { 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 - || permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) + || service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) || "127.0.0.1".equalsIgnoreCase(ip) || "localhost".equalsIgnoreCase(ip)) { return false; diff --git a/src/main/java/fr/xephi/authme/service/CommonService.java b/src/main/java/fr/xephi/authme/service/CommonService.java index cea51ea01..d2381a455 100644 --- a/src/main/java/fr/xephi/authme/service/CommonService.java +++ b/src/main/java/fr/xephi/authme/service/CommonService.java @@ -65,16 +65,6 @@ public class CommonService { messages.send(sender, key, replacements); } - /** - * Retrieves a message. - * - * @param key the key of the message - * @return the message, split by line - */ - public String[] retrieveMessage(MessageKey key) { - return messages.retrieve(key); - } - /** * Retrieves a message in one piece. * @@ -102,6 +92,7 @@ public class CommonService { * @param player the player to process * @param group the group to add the player to */ + // TODO ljacqu 20170304: Move this out of CommonService public void setGroup(Player player, AuthGroupType group) { authGroupHandler.setGroup(player, group); } diff --git a/src/main/java/fr/xephi/authme/service/ValidationService.java b/src/main/java/fr/xephi/authme/service/ValidationService.java index 7c7abf785..dd1f6e51e 100644 --- a/src/main/java/fr/xephi/authme/service/ValidationService.java +++ b/src/main/java/fr/xephi/authme/service/ValidationService.java @@ -1,6 +1,7 @@ package fr.xephi.authme.service; import ch.jalu.configme.properties.Property; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.message.MessageKey; @@ -115,9 +116,10 @@ public class ValidationService implements Reloadable { } String countryCode = geoIpService.getCountryCode(hostAddress); - return validateWhitelistAndBlacklist(countryCode, - ProtectionSettings.COUNTRIES_WHITELIST, - ProtectionSettings.COUNTRIES_BLACKLIST); + boolean isCountryAllowed = validateWhitelistAndBlacklist(countryCode, + ProtectionSettings.COUNTRIES_WHITELIST, ProtectionSettings.COUNTRIES_BLACKLIST); + ConsoleLogger.debug("Country code `{0}` for `{1}` is allowed: {2}", countryCode, hostAddress, isCountryAllowed); + return isCountryAllowed; } /** @@ -194,6 +196,7 @@ public class ValidationService implements Reloadable { public MessageKey getMessageKey() { return messageKey; } + public String[] getArgs() { return args; } diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java index d87ebd5e3..f996640c9 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java @@ -74,7 +74,7 @@ public class CommandManager implements Reloadable { private void executeCommands(Player player, List commands) { for (Command command : commands) { - final String execution = command.getCommand().replace("%p", player.getName()); + final String execution = command.getCommand(); if (Executor.CONSOLE.equals(command.getExecutor())) { bukkitService.dispatchConsoleCommand(execution); } else { diff --git a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java index d4e80a1c7..e752057c1 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java @@ -54,6 +54,18 @@ public final class HooksSettings implements SettingsHolder { 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 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_"); diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeService.java b/src/main/java/fr/xephi/authme/task/purge/PurgeService.java index fed077682..fe6d2fbf8 100644 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeService.java +++ b/src/main/java/fr/xephi/authme/task/purge/PurgeService.java @@ -9,14 +9,13 @@ import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.Utils; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; import javax.inject.Inject; import java.util.Calendar; import java.util.Collection; import java.util.Set; -// TODO: move into services. -sgdc3 +import static fr.xephi.authme.util.Utils.logAndSendMessage; /** * Initiates purge tasks. @@ -119,12 +118,4 @@ public class PurgeService { void executePurge(Collection players, Collection names) { purgeExecutor.executePurge(players, names); } - - private static void logAndSendMessage(CommandSender sender, String message) { - ConsoleLogger.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); - } - } } diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index b7628147b..4d6983df5 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -1,6 +1,8 @@ package fr.xephi.authme.util; import fr.xephi.authme.ConsoleLogger; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; import java.util.Collection; import java.util.regex.Pattern; @@ -51,6 +53,22 @@ public final class Utils { } } + /** + * 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) { + ConsoleLogger.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); + } + } + /** * Null-safe way to check whether a collection is empty or not. * diff --git a/src/main/resources/messages/help_pt.yml b/src/main/resources/messages/help_pt.yml new file mode 100644 index 000000000..2b2ead6c3 --- /dev/null +++ b/src/main/resources/messages/help_pt.yml @@ -0,0 +1,45 @@ +# 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/messages_bg.yml b/src/main/resources/messages/messages_bg.yml index 38e79face..a39a9d536 100644 --- a/src/main/resources/messages/messages_bg.yml +++ b/src/main/resources/messages/messages_bg.yml @@ -1,105 +1,104 @@ # Registration -reg_msg: '&cМоля регистрирай се с "/register <парола> <парола>"' +reg_msg: '&3Моля регистрирайте се с: /register парола парола' usage_reg: '&cКоманда: /register парола парола' -reg_only: '&fСамо за регистрирани! Моля посети http://example.com за регистрация' -# TODO kicked_admin_registered: 'An admin just registered you; please log in again' -registered: '&cУспешно премахната регистрация!' +reg_only: '&4Само регистрирани потребители могат да влизат в сървъра! Моля посетете http://example.com, за да се регистрирате!' +kicked_admin_registered: 'Ти беше регистриран от администратора, моля влезте отново' +registered: '&2Успешна регистрация!' reg_disabled: '&cРегистрациите са изключени!' -user_regged: '&cПотребителското име е заето!' +user_regged: '&cПотребителското име е заетo!' # Password errors on registration -password_error: '&fПаролата не съвпада' -# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...' -# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -pass_len: '&cВашета парола не е достатъчно дълга или къса.' +password_error: '&cПаролите не съвпадат, провете ги отново!' +password_error_nick: '&cНе можеш да използваш потребителското си име за парола, моля изберете друга парола.' +password_error_unsafe: '&cИзбраната парола не е безопасна, моля изберете друга парола.' +password_error_chars: '&4Паролата съдържа непозволени символи. Позволени символи: REG_EX' +pass_len: '&cПаролата е твърде къса или прекалено дълга! Моля опитайте с друга парола.' # Login usage_log: '&cКоманда: /login парола' wrong_pwd: '&cГрешна парола!' -login: '&cВход успешен!' -login_msg: '&cМоля влез с "/login парола"' -timeout: '&fВремето изтече, опитай отново!' +login: '&2Успешен вход!' +login_msg: '&cМоля влезте с: /login парола' +timeout: '&4Времето за вход изтече, беше кикнат от сървъра. Моля опитайте отново!' # Errors -unknown_user: '&cПотребителя не е регистриран' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' +unknown_user: '&cПотребителското име не е регистрирано!' +denied_command: '&cЗа да използваш тази команда трябва да си си влезнал в акаунта!' +denied_chat: '&cЗа да пишеш в чата трябва даи сиси влезнал в акаунта!' not_logged_in: '&cНе си влязъл!' -# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' -# TODO: Missing tags %reg_count, %max_acc, %reg_names -max_reg: '&fТи достигна максималния брой регистрации!' -no_perm: '&cНямаш Достъп!' -error: '&fПолучи се грешка; Моля свържете се с админ' -unsafe_spawn: '&fТвоята локация когато излезе не беше безопасна, телепортиран си на Spawn!' -kick_forvip: '&cVIP влезе докато сървъра е пълен, ти беше изгонен!' +tempban_max_logins: '&cТи беше баннат временно, понеже си сгрешил паролата прекалено много пъти.' +max_reg: '&cТи си достигнал максималният брой регистрации (%reg_count/%max_acc %reg_names)!' +no_perm: '&4Нямаш нужните права за това действие!' +error: '&4Получи се неочаквана грешка, моля свържете се с администратора!' +unsafe_spawn: '&cКогато излезе твоето местоположение не беше безопастно, телепортиран си на Spawn.' +kick_forvip: '&3VIP потребител влезе докато сървъра беше пълен, ти беше изгонен!' # AntiBot -# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' -antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично включен, открита е потенциална атака!' -antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключване след %m Минути.' +kick_antibot: 'Защитата от ботове е включена! Трябва да изчакаш няколко минути преди да влезеш в сървъра.' +antibot_auto_enabled: '&4Защитата за ботове е включена заради потенциална атака!' +antibot_auto_disabled: '&2Защитата за ботове ще се изключи след %m минута/и!' # Other messages -unregistered: '&cУспешно от-регистриран!' -# TODO accounts_owned_self: 'You own %count accounts:' -# TODO accounts_owned_other: 'The player %name has %count accounts:' -# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url' -# TODO recovery_code_sent: 'A recovery code to reset your password has been sent to your email.' -# TODO recovery_code_incorrect: 'The recovery code is not correct! Use "/email recovery [email]" to generate a new one' -vb_nonActiv: '&fТвоята регистрация не е активирана, моля провери своя Имейл!' +unregistered: '&cРегистрацията е премахната успешно!' +accounts_owned_self: 'Претежаваш %count акаунт/а:' +accounts_owned_other: 'Потребителят %name има %count акаунт/а:' +two_factor_create: '&2Кода е %code. Можеш да го провериш оттука: %url' +recovery_code_sent: 'Възстановяващият код беше изпратен на твоят email адрес.' +recovery_code_incorrect: 'Възстановяващият код е неправилен! Използвайте: /email recovery имейл, за да генерирате нов' +vb_nonActiv: '&cТвоят акаунт все още не е актириван, моля провете своят email адрес!' usage_unreg: '&cКоманда: /unregister парола' -pwd_changed: '&cПаролата е променена!' -logged_in: '&cВече сте влязъл!' -logout: '&cУспешен изход от регистрацията!' -reload: '&fКонфигурацията презаредена!' -usage_changepassword: '&fКоманда: /changepassword СтараПарола НоваПарола' +pwd_changed: '&2Паротала е променена успешно!' +logged_in: '&cВече си вписан!' +logout: '&2Излязохте успешно!' +reload: '&2Конфигурацията и база данните бяха презаредени правилно!' +usage_changepassword: '&cКоманда: /changepassword Стара-Парола Нова-Парола' # Session messages -# TODO invalid_session: '&cYour IP has been changed and your session data has expired!' -valid_session: '&aСесията продължена!' +invalid_session: '&cТвоят IP се е променил и сесията беше прекратена.' +valid_session: '&2Сесията е продължена.' # Error messages when joining -name_len: '&cТвоя никнейм е твърде малък или голям' -regex: '&cТвоя никнейм съдържа забранени знацхи. Позволените са: REG_EX' -country_banned: 'Твоята държава е забранена в този сървър!' -# TODO not_owner_error: 'You are not the owner of this account. Please choose another name!' -kick_fullserver: '&cСървъра е пълен, Съжеляваме!' -same_nick: '&fПотребител с този никнейм е в игра' -# TODO invalid_name_case: 'You should join using username %valid, not %invalid.' -# TODO same_ip_online: 'A player with the same IP is already in game!' +name_len: '&4Потребителското име е прекалено късо или дълга. Моля опитайте с друго потребителско име!' +regex: '&4Потребителското име съдържа забранени знаци. Позволени знаци: REG_EX' +country_banned: '&4Твоята държава е забранена в този сървър!' +not_owner_error: 'Ти не си собственика на този акаунт. Моля избери друго потребителско име!' +kick_fullserver: '&4Сървъра е пълен, моля опитайте отново!' +same_nick: '&4Вече има потребител, който играете в сървъра със същото потребителско име!' +invalid_name_case: 'Трябва да влезеш с %valid, а не с %invalid.' +same_ip_online: 'Вече има потребител със същото IP в сървъра!' # Email -usage_email_add: '&fКоманда: /email add ' -usage_email_change: '&fКоманда: /email change <СтарИмейл> <НовИмейл> ' -usage_email_recovery: '&fКоманда: /email recovery <имейл>' -new_email_invalid: '[AuthMe] Новия имейл е грешен!' -old_email_invalid: '[AuthMe] Стария имейл е грешен!' -email_invalid: '[AuthMe] Грешен имейл' -email_added: '[AuthMe] Имейла добавен !' -email_confirm: '[AuthMe] Потвърди своя имейл !' -email_changed: '[AuthMe] Имейла е сменен !' -email_send: '[AuthMe] Изпраен е имейл !' -# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' -# TODO email_show: '&2Your current email address is: &f%email' -# TODO incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.' -# TODO email_already_used: '&4The email address is already being used' -# TODO email_send_failure: 'The email could not be sent. Please contact an administrator.' -# TODO show_no_email: '&2You currently don''t have email address associated with this account.' -add_email: '&cМоля добави своя имейл с : /email add имейл имейл' -recovery_email: '&cЗабравихте своята парола? Моля използвай /email recovery <имейл>' -# TODO email_cooldown_error: '&cAn email was already sent recently. You must wait %time before you can send a new one.' +usage_email_add: '&cКоманда: /email add имейл имейл' +usage_email_change: '&cКоманда: /email change Стар-Имейл Нов-Имейл' +usage_email_recovery: '&cКоманда: /email recovery имейл' +new_email_invalid: '&cНовият имейл е грешен, опитайте отново!' +old_email_invalid: '&cСтарият имейл е грешен, опитайте отново!' +email_invalid: '&cИмейла е невалиден, опитайте с друг!' +email_added: '&2Имейл адреса е добавен!' +email_confirm: '&cМоля потвърди своя имейл адрес!' +email_changed: '&2Имейл адреса е сменен!' +email_send: '&2Възстановяващият имейл е изпратен успешно. Моля провете пощата си!' +email_exists: '&cВъзстановяващият имейл е бил изпратен. Може да го откажеш или изпратиш отново с тази команда:' +email_show: '&2Твоят имейл адрес е: &f%email' +incomplete_email_settings: 'Грешка: Не всички настройки са написани за изпращане на имейл адрес. Моля свържете се с администратора!' +email_already_used: '&4Имейл адреса вече се използва, опитайте с друг.' +email_send_failure: 'Съобщението не беше изпратено. Моля свържете се с администратора.' +show_no_email: '&2Няма добавен имейл адрес към акаунта.' +add_email: '&3Моля добавете имейл адрес към своят акаунт: /email add имейл имейл' +recovery_email: '&3Забравена парола? Използвайте: /email recovery имейл' +email_cooldown_error: '&cВече е бил изпратен имейл адрес. Трябва а изчакаш %time преди да пратиш нов.' # Captcha -usage_captcha: '&cYou need to type a captcha, please type: /captcha ' -wrong_captcha: '&cГрешен код, използвай : /captcha THE_CAPTCHA' -valid_captcha: '&cТвоя код е валиден!' +usage_captcha: '&3Моля въведе цифрите/буквите от капчата: /captcha ' +wrong_captcha: '&cКода е грешен, използвайте: "/captcha THE_CAPTCHA" в чата!' +valid_captcha: '&2Кода е валиден!' # Time units -# TODO second: 'second' -# TODO seconds: 'seconds' -# TODO minute: 'minute' -# TODO minutes: 'minutes' -# TODO hour: 'hour' -# TODO hours: 'hours' -# TODO day: 'day' -# TODO days: 'days' +second: 'секунда' +seconds: 'секунди' +minute: 'минута' +minutes: 'минути' +hour: 'час' +hours: 'часа' +day: 'ден' +days: 'дена' diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml index ac7415718..5ee7a5646 100644 --- a/src/main/resources/messages/messages_es.yml +++ b/src/main/resources/messages/messages_es.yml @@ -89,7 +89,7 @@ email_send_failure: 'No se ha podido enviar el correo electrónico. Por favor, c show_no_email: '&2No tienes ningun E-Mail asociado en esta cuenta.' add_email: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail' recovery_email: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery ' -# TODO email_cooldown_error: '&cAn email was already sent recently. You must wait %time before you can send a new one.' +email_cooldown_error: '&cEl correo ha sido enviado recientemente. Debes esperar %time antes de volver a enviar uno nuevo.' # Captcha usage_captcha: '&cUso: /captcha ' @@ -97,11 +97,11 @@ wrong_captcha: '&cCaptcha incorrecto, por favor usa: /captcha THE_CAPTCHA' valid_captcha: '&c¡ Captcha ingresado correctamente !' # Time units -# TODO second: 'second' -# TODO seconds: 'seconds' -# TODO minute: 'minute' -# TODO minutes: 'minutes' -# TODO hour: 'hour' -# TODO hours: 'hours' -# TODO day: 'day' -# TODO days: 'days' +second: 'segundo' +seconds: 'segundos' +minute: 'minuto' +minutes: 'minutos' +hour: 'hora' +hours: 'horas' +day: 'día' +days: 'días' diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionConsistencyTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionConsistencyTest.java new file mode 100644 index 000000000..18ab9fd22 --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugSectionConsistencyTest.java @@ -0,0 +1,51 @@ +package fr.xephi.authme.command.executable.authme.debug; + +import fr.xephi.authme.ClassCollector; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * Consistency tests for {@link DebugSection} implementors. + */ +public class DebugSectionConsistencyTest { + + private static List> debugClasses; + + @BeforeClass + public static void collectClasses() { + debugClasses = new ClassCollector("src/main/java", "fr/xephi/authme/command/executable/authme/debug") + .collectClasses(); + } + + @Test + public void shouldAllBePackagePrivate() { + for (Class clazz : debugClasses) { + if (clazz != DebugCommand.class) { + assertThat(clazz + " should be package-private", + Modifier.isPublic(clazz.getModifiers()), equalTo(false)); + } + } + } + + @Test + public void shouldHaveDifferentSubcommandName() throws IllegalAccessException, InstantiationException { + Set names = new HashSet<>(); + for (Class clazz : debugClasses) { + if (DebugSection.class.isAssignableFrom(clazz) && !clazz.isInterface()) { + DebugSection debugSection = (DebugSection) clazz.newInstance(); + if (!names.add(debugSection.getName())) { + fail("Encountered name '" + debugSection.getName() + "' a second time in " + clazz); + } + } + } + } +} diff --git a/src/test/java/fr/xephi/authme/mail/SendMailSSLTest.java b/src/test/java/fr/xephi/authme/mail/SendMailSSLTest.java index 835d4b49b..74318498f 100644 --- a/src/test/java/fr/xephi/authme/mail/SendMailSSLTest.java +++ b/src/test/java/fr/xephi/authme/mail/SendMailSSLTest.java @@ -4,8 +4,10 @@ import ch.jalu.injector.testing.BeforeInjecting; import ch.jalu.injector.testing.DelayedInjectionRunner; import ch.jalu.injector.testing.InjectDelayed; import fr.xephi.authme.TestHelper; +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 org.apache.commons.mail.EmailException; import org.apache.commons.mail.HtmlEmail; import org.junit.BeforeClass; @@ -49,6 +51,7 @@ public class SendMailSSLTest { public void initFields() throws IOException { given(settings.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn("mail@example.org"); given(settings.getProperty(EmailSettings.MAIL_PASSWORD)).willReturn("pass1234"); + given(settings.getProperty(PluginSettings.LOG_LEVEL)).willReturn(LogLevel.INFO); } @Test @@ -67,6 +70,7 @@ public class SendMailSSLTest { given(settings.getProperty(EmailSettings.MAIL_ACCOUNT)).willReturn(senderAccount); String senderName = "Server administration"; given(settings.getProperty(EmailSettings.MAIL_SENDER_NAME)).willReturn(senderName); + given(settings.getProperty(PluginSettings.LOG_LEVEL)).willReturn(LogLevel.DEBUG); // when HtmlEmail email = sendMailSSL.initializeMail("recipient@example.com"); diff --git a/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java b/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java index 2caaaef76..9f21b7ba4 100644 --- a/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java +++ b/src/test/java/fr/xephi/authme/process/login/AsynchronousLoginTest.java @@ -7,7 +7,6 @@ import fr.xephi.authme.data.limbo.LimboService; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; import fr.xephi.authme.message.MessageKey; -import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; @@ -61,8 +60,6 @@ public class AsynchronousLoginTest { private LimboService limboService; @Mock private BukkitService bukkitService; - @Mock - private PermissionsManager permissionsManager; @BeforeClass public static void initLogger() { @@ -182,7 +179,7 @@ public class AsynchronousLoginTest { // given Player player = mockPlayer("Carl"); given(commonService.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP)).willReturn(2); - given(permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(false); + given(commonService.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(false); mockOnlinePlayersInBukkitService(); // when @@ -190,7 +187,7 @@ public class AsynchronousLoginTest { // then assertThat(result, equalTo(false)); - verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); + verify(commonService).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); verify(bukkitService).getOnlinePlayers(); } @@ -213,14 +210,14 @@ public class AsynchronousLoginTest { // given Player player = mockPlayer("Frank"); given(commonService.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP)).willReturn(1); - given(permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(true); + given(commonService.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(true); // when boolean result = asynchronousLogin.hasReachedMaxLoggedInPlayersForIp(player, "127.0.0.4"); // then assertThat(result, equalTo(false)); - verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); + verify(commonService).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); verifyZeroInteractions(bukkitService); } @@ -229,7 +226,7 @@ public class AsynchronousLoginTest { // given Player player = mockPlayer("Ian"); given(commonService.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP)).willReturn(2); - given(permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(false); + given(commonService.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(false); mockOnlinePlayersInBukkitService(); // when @@ -237,7 +234,7 @@ public class AsynchronousLoginTest { // then assertThat(result, equalTo(true)); - verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); + verify(commonService).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS); verify(bukkitService).getOnlinePlayers(); } diff --git a/src/test/java/fr/xephi/authme/service/CommonServiceTest.java b/src/test/java/fr/xephi/authme/service/CommonServiceTest.java index 7927f826f..ad0b7e73f 100644 --- a/src/test/java/fr/xephi/authme/service/CommonServiceTest.java +++ b/src/test/java/fr/xephi/authme/service/CommonServiceTest.java @@ -84,21 +84,6 @@ public class CommonServiceTest { verify(messages).send(sender, key, replacements); } - @Test - public void shouldRetrieveMessage() { - // given - MessageKey key = MessageKey.ACCOUNT_NOT_ACTIVATED; - String[] lines = new String[]{"First message line", "second line"}; - given(messages.retrieve(key)).willReturn(lines); - - // when - String[] result = commonService.retrieveMessage(key); - - // then - assertThat(result, equalTo(lines)); - verify(messages).retrieve(key); - } - @Test public void shouldRetrieveSingleMessage() { // given diff --git a/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java b/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java index d4e3f8cda..e07ea1c2e 100644 --- a/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java +++ b/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java @@ -58,7 +58,7 @@ public class PluginHookServiceTest { assertThat(pluginHookService.isEssentialsAvailable(), equalTo(true)); } - // Note ljacqu 20160312: Cannot test with Multiverse or CombatTagPlus because their classes are declared final + // Note ljacqu 20160312: Cannot test with CombatTagPlus because its class is declared final @Test public void shouldHookIntoEssentialsAtInitialization() { diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index 458023d6d..cbb64f370 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -1,13 +1,20 @@ package fr.xephi.authme.util; import fr.xephi.authme.TestHelper; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; import org.junit.BeforeClass; import org.junit.Test; +import java.util.logging.Logger; import java.util.regex.Pattern; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link Utils}. @@ -49,6 +56,49 @@ public class UtilsTest { TestHelper.validateHasOnlyPrivateEmptyConstructor(Utils.class); } + @Test + public void shouldLogAndSendMessage() { + // given + Logger logger = TestHelper.setupLogger(); + Player player = mock(Player.class); + String message = "Finished adding foo to the bar"; + + // when + Utils.logAndSendMessage(player, message); + + // then + verify(logger).info(message); + verify(player).sendMessage(message); + } + + @Test + public void shouldHandleNullAsCommandSender() { + // given + Logger logger = TestHelper.setupLogger(); + String message = "Test test, test."; + + // when + Utils.logAndSendMessage(null, message); + + // then + verify(logger).info(message); + } + + @Test + public void shouldNotSendToCommandSenderTwice() { + // given + Logger logger = TestHelper.setupLogger(); + CommandSender sender = mock(ConsoleCommandSender.class); + String message = "Test test, test."; + + // when + Utils.logAndSendMessage(sender, message); + + // then + verify(logger).info(message); + verifyZeroInteractions(sender); + } + @Test public void shouldCheckIfClassIsLoaded() { // given / when / then