diff --git a/docs/config.md b/docs/config.md index 2483ed4fb..2a664563b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,5 +1,5 @@ - + ## AuthMe Configuration The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, @@ -63,8 +63,8 @@ DataSource: mySQLlastlocYaw: 'yaw' # Column for storing player LastLocation - Pitch mySQLlastlocPitch: 'pitch' - # Overrides the size of the DB Connection Pool, -1 = Auto - poolSize: -1 + # Overrides the size of the DB Connection Pool, default = 10 + poolSize: 10 # 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 maxLifetime: 1800 @@ -560,4 +560,4 @@ To change settings on a running server, save your changes to config.yml and use --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Tue Nov 28 12:49:57 CET 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Wed Dec 13 23:12:29 CET 2017 diff --git a/pom.xml b/pom.xml index 1e785bf0d..a3ac7819e 100644 --- a/pom.xml +++ b/pom.xml @@ -329,7 +329,7 @@ com.google.guava guava - 23.2-jre + 23.5-jre compile true @@ -364,7 +364,7 @@ com.zaxxer HikariCP - 2.7.2 + 2.7.4 compile @@ -396,7 +396,7 @@ de.mkammerer argon2-jvm-nolibs - 2.2 + 2.3 @@ -462,7 +462,7 @@ me.lucko.luckperms luckperms-api - 3.4-SNAPSHOT + 4.0-SNAPSHOT provided @@ -740,7 +740,7 @@ org.mockito mockito-core test - 2.10.0 + 2.13.0 hamcrest-core @@ -753,7 +753,7 @@ org.xerial sqlite-jdbc - 3.20.0 + 3.21.0.1 test diff --git a/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java b/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java index d4fae3ff0..25bdb209e 100644 --- a/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java +++ b/src/main/java/fr/xephi/authme/api/v3/AuthMeApi.java @@ -12,11 +12,14 @@ 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 javax.inject.Inject; + +import java.time.Instant; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -159,18 +162,38 @@ public class AuthMeApi { } /** - * Get the last login date of a player. + * 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 && auth.getLastLogin() != null) { - return new Date(auth.getLastLogin()); + if (auth != null) { + return auth.getLastLogin(); } return null; } 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 index 7787bb569..339980a34 100644 --- a/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/email/RecoverEmailCommand.java @@ -7,6 +7,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.message.MessageKey; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.service.PasswordRecoveryService; import fr.xephi.authme.service.RecoveryCodeService; @@ -39,6 +40,9 @@ public class RecoverEmailCommand extends PlayerCommand { @Inject private RecoveryCodeService recoveryCodeService; + @Inject + private BukkitService bukkitService; + @Override protected void runCommand(Player player, List arguments) { final String playerMail = arguments.get(0); @@ -66,13 +70,15 @@ public class RecoverEmailCommand extends PlayerCommand { return; } - 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); - } + 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 diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index eb6019ca2..4e6695787 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -98,9 +98,6 @@ public class MySQL implements DataSource { this.col = new Columns(settings); this.sqlExtension = extensionsFactory.buildExtension(col); this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); - if (poolSize == -1) { - poolSize = Utils.getCoreCount() * 3; - } this.maxLifetime = settings.getProperty(DatabaseSettings.MYSQL_CONNECTION_MAX_LIFETIME); this.useSsl = settings.getProperty(DatabaseSettings.MYSQL_USE_SSL); } @@ -116,7 +113,6 @@ public class MySQL implements DataSource { ds.setMaximumPoolSize(poolSize); ds.setMaxLifetime(maxLifetime * 1000); - // Database URL ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); diff --git a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java index 4f5dcb370..2c30c030e 100644 --- a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java +++ b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java @@ -102,7 +102,7 @@ public class LuckPermsHandler implements PermissionHandler { } Group permissionGroup = luckPermsApi.getGroup(group); - boolean result = permissionGroup != null && user.isInGroup(permissionGroup); + boolean result = permissionGroup != null && user.inheritsGroup(permissionGroup); luckPermsApi.cleanupUser(user); return result; diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java index fb47f7806..7a684a3da 100644 --- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java +++ b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java @@ -10,6 +10,7 @@ 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), diff --git a/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java b/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java new file mode 100644 index 000000000..2b94dc038 --- /dev/null +++ b/src/main/java/fr/xephi/authme/security/crypts/CmwCrypt.java @@ -0,0 +1,14 @@ +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/service/bungeecord/BungeeSender.java b/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java index 4394651be..0b5e6ca64 100644 --- a/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java +++ b/src/main/java/fr/xephi/authme/service/bungeecord/BungeeSender.java @@ -3,6 +3,7 @@ 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.service.BukkitService; import fr.xephi.authme.settings.Settings; @@ -11,6 +12,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.Messenger; import javax.inject.Inject; +import java.io.Console; public class BungeeSender implements SettingsDependent { @@ -76,6 +78,10 @@ public class BungeeSender implements SettingsDependent { */ public void sendAuthMeBungeecordMessage(String type, String playerName) { if (isEnabled) { + if(!plugin.isEnabled()) { + ConsoleLogger.debug("Tried to send a " + type + " bungeecord message but the plugin was disabled!"); + return; + } sendBungeecordMessage("AuthMe", type, playerName.toLowerCase()); } } diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java index 9be278807..641492be2 100644 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -70,6 +70,7 @@ public class SettingsMigrationService extends PlainMigrationService { | performMailTextToFileMigration(resource) | migrateJoinLeaveMessages(resource) | migrateForceSpawnSettings(resource) + | migratePoolSizeSetting(resource) | changeBooleanSettingToLogLevelProperty(resource) | hasOldHelpHeaderProperty(resource) | hasSupportOldPasswordProperty(resource) @@ -194,6 +195,21 @@ public class SettingsMigrationService extends PlainMigrationService { | moveProperty(oldForceWorlds, FORCE_SPAWN_ON_WORLDS, resource); } + /** + * Detects the old auto poolSize value and replaces it with the default value. + * + * @param resource The property resource + * @return True if the configuration has changed, false otherwise + */ + private static boolean migratePoolSizeSetting(PropertyResource resource) { + Integer oldValue = resource.getInt("DataSource.poolSize"); + if(oldValue == null || oldValue > 0) { + return false; + } + resource.setValue("DataSource.poolSize", 10); + return true; + } + /** * Changes the old boolean property "hide spam from console" to the new property specifying * the log level. diff --git a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java index 31c629833..66ddd3cd5 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java @@ -123,9 +123,9 @@ public final class DatabaseSettings implements SettingsHolder { public static final Property MYSQL_COL_GROUP = newProperty("ExternalBoardOptions.mySQLColumnGroup", ""); - @Comment("Overrides the size of the DB Connection Pool, -1 = Auto") + @Comment("Overrides the size of the DB Connection Pool, default = 10") public static final Property MYSQL_POOL_SIZE = - newProperty("DataSource.poolSize", -1); + 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"}) diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index ad4ccb9e4..4db7f61bc 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -96,15 +96,6 @@ public final class Utils { return coll == null || coll.isEmpty(); } - /** - * Return the available core count of the JVM. - * - * @return the core count - */ - public static int getCoreCount() { - return Runtime.getRuntime().availableProcessors(); - } - /** * Returns whether the given email is empty or equal to the standard "undefined" email address. * diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml index aca6307ee..ad0231e14 100644 --- a/src/main/resources/messages/messages_fr.yml +++ b/src/main/resources/messages/messages_fr.yml @@ -8,8 +8,8 @@ reg_msg: '&cPour vous inscrire, utilisez "/register ' reg_only: 'Seul les joueurs enregistrés sont admis!%nl%Veuillez vous rendre sur http://example.com pour plus d''infos.' kicked_admin_registered: 'Un admin vient de vous inscrire, veuillez vous reconnecter.' -registered: '&aInscription effectué !' -reg_disabled: '&cL''inscription est désactivé.' +registered: '&aInscription effectuée !' +reg_disabled: '&cL''inscription est désactivée.' user_regged: '&cUtilisateur déjà inscrit.' # Erreurs MDP pour l'inscription @@ -32,27 +32,27 @@ denied_command: '&cVous devez être connecté pour pouvoir utiliser cette comman denied_chat: '&cVous devez être connecté pour pouvoir écrire dans le chat.' not_logged_in: '&cUtilisateur non connecté !' tempban_max_logins: '&cVous êtes temporairement banni suite à plusieurs échecs de connexions !' -max_reg: 'Vous avez atteint la limite d''inscription! &o(%reg_count/%max_acc : %reg_names)' +max_reg: 'Vous avez atteint la limite d''inscription !%nl%&cVous avez %reg_count sur %max_acc : %reg_names' no_perm: '&cVous n''êtes pas autorisé à utiliser cette commande.' error: '&cUne erreur est apparue, veuillez contacter un administrateur.' kick_forvip: 'Un joueur VIP a rejoint le serveur à votre place (serveur plein).' # AntiBot -kick_antibot: 'AntiBot est activé, veuillez attendre %m minutes avant de joindre le serveur.' -antibot_auto_enabled: 'AntiBot activé automatiquement à cause de nombreuses connexions !' -antibot_auto_disabled: 'AntiBot désactivé automatiquement après %m minutes, espérons que l''invasion soit arrêtée !' +kick_antibot: 'L''AntiBot est activé, veuillez attendre %m minutes avant de joindre le serveur.' +antibot_auto_enabled: 'L''AntiBot a été activé automatiquement à cause de nombreuses connexions !' +antibot_auto_disabled: 'L''AntiBot a été désactivé automatiquement après %m minutes, espérons que l''invasion se soit arrêtée !' # Autres messages unregistered: '&aCompte supprimé !' accounts_owned_self: 'Vous avez %count comptes:' accounts_owned_other: 'Le joueur %name a %count comptes:' two_factor_create: '&aVotre code secret est &2%code&a. Vous pouvez le scanner depuis &2%url' -recovery_code_sent: 'Un code de récupération a été envoyé à votre adresse email afin de réinitialiser votre mot de passe.' +recovery_code_sent: 'Un code de récupération a été envoyé à votre email afin de réinitialiser votre mot de passe.' recovery_code_incorrect: '&cLe code de réinitialisation est incorrect! Il vous reste %count% essai(s).' -recovery_tries_exceeded: 'Vous avez atteint le nombre maximum d''essais pour rentrer le code.%nl%Refaites "/email recovery [email]" pour en régénérer à nouveau.' -recovery_code_correct: 'Code de réinitialisation correct !' -recovery_change_password: 'Veuillez faire "/email setpassword " pour changer votre mot de passe directement.' -vb_nonActiv: '&fCe compte n''est pas actif, consultez vos emails !' +recovery_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.' +recovery_code_correct: '&aCode de réinitialisation correct !' +recovery_change_password: 'Veuillez faire "/email setpassword " pour changer votre mot de passe directement.' +vb_nonActiv: '&fCe compte n''est pas actif, consultez vos mails !' usage_unreg: '&cPour supprimer votre compte, utilisez "/unregister "' pwd_changed: '&aMot de passe changé avec succès !' logged_in: '&aVous êtes déjà connecté.' @@ -84,27 +84,27 @@ email_invalid: '&cL''email inscrit est invalide !' email_added: '&aEmail enregistré. En cas de perte de MDP, faites "/email recover "' email_confirm: '&cLa confirmation de l''email est manquante ou éronnée.' email_changed: '&aVotre email a été mis à jour.' -email_send: '&aEmail de récupération envoyé !' -email_show: '&2Votre adresse email actuelle est: &f%email' +email_send: '&aMail de récupération envoyé !' +email_show: '&fL''email enregistré pour votre compte est: %email' incomplete_email_settings: '&cErreur : Tous les paramètres requis ne sont pas présent pour l''envoi de mail, veuillez contacter un admin.' -email_already_used: '&cCette adresse email est déjà utilisée !' -email_send_failure: '&cL''email n''a pas pu être envoyé. Veuillez contacter un admin.' -show_no_email: '&c&oVous n''avez aucune adresse mail enregistré sur votre compte.' -add_email: '&cLier votre email à votre compte: /email add ' +email_already_used: '&cCet email est déjà utilisé !' +email_send_failure: '&cLe mail n''a pas pu être envoyé. Veuillez contacter un admin.' +show_no_email: '&c&oVous n''avez aucun email enregistré sur votre compte.' +add_email: '&cLiez votre email à votre compte en faisant "/email add "' recovery_email: '&cVous avez oublié votre Mot de Passe? Utilisez "/email recovery "' change_password_expired: 'Vous ne pouvez pas changer votre mot de passe avec cette commande.' -email_cooldown_error: '&cUn email de récupération a déjà été envoyé récemment. Veuillez attendre %time pour le demander de nouveau.' +email_cooldown_error: '&cUn mail de récupération a déjà été envoyé récemment. Veuillez attendre %time pour le demander de nouveau.' # Captcha usage_captcha: '&cTrop de tentatives de connexion échouées, utilisez: /captcha ' wrong_captcha: '&cCaptcha incorrect, écrivez de nouveau: /captcha THE_CAPTCHA' -valid_captcha: '&aCaptché validé! Veuillez maintenant vous connecter.' +valid_captcha: '&aCaptcha validé! Veuillez maintenant vous connecter.' # Vérification par code 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.' usage_verification_code: '&cUsage: /verification ' -incorrect_verification_code: '&cCode incorrect !%nl%&cVeuillez taper "/verification " dans le chat en utilisant le code reçu par email.' -verification_code_verified: '&aVotre identité a bien été vérifié !%nl%&aVous pouvez désormais utiliser la commande souhaitée durant toute la session.' +incorrect_verification_code: '&cCode incorrect !%nl%&cVeuillez taper "/verification " dans le chat en utilisant le code reçu par mail.' +verification_code_verified: '&aVotre identité a bien été vérifiée !%nl%&aVous pouvez désormais utiliser la commande souhaitée durant toute la session.' verification_code_already_verified: '&aVous êtes déjà autorisé à utiliser les commandes sensibles durant votre session actuelle.' verification_code_expired: '&cVotre code d''identification a expiré !%nl%&cVeuillez re-exécuter une commande sensible pour recevoir un nouveau code.' verification_code_email_needed: '&cAfin de vérifier votre identité, vous devez avoir un email lié à votre compte.%nl%&cPour cela, faites "/email add "' diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml index 3df7d1b28..af5566392 100644 --- a/src/main/resources/messages/messages_zhtw.yml +++ b/src/main/resources/messages/messages_zhtw.yml @@ -6,36 +6,36 @@ reg_msg: '&b【AuthMe】&6請使用 "&c/register <密碼> <確認密碼>" 來註冊。' usage_reg: '&b【AuthMe】&6用法: &c"/register <密碼> <確認密碼>"' reg_only: '&b【AuthMe】&6請到下列網站 :「 https://example.tw 」 進行註冊' -# TODO kicked_admin_registered: 'An admin just registered you; please log in again' +kicked_admin_registered: '&b【AuthMe】管理員已為你完成註冊,請重新登入' registered: '&b【AuthMe】&6你已成功註冊' reg_disabled: '&b【AuthMe】&6已關閉註冊功能' user_regged: '&b【AuthMe】&6這個帳號已經被註冊過了!' # Password errors on registration password_error: '&b【AuthMe】&6兩次輸入的密碼不一致!' -password_error_nick: '&b【AuthMe】&6你不可以用你的 ID ( 名稱 ) 來當作密碼 !' -password_error_unsafe: '&b【AuthMe】&6你不可以使用這個不安全的密碼' -# TODO password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' -pass_len: '&b【AuthMe】&6你的密碼 超過最大字數 / 小於最小字數' +password_error_nick: '&b【AuthMe】&6您不可以用你的 ID ( 名稱 ) 來當作密碼 !' +password_error_unsafe: '&b【AuthMe】&6您不可以使用這個不安全的密碼。' +password_error_chars: '&b【AuthMe】&4您設定的密碼使用了非法字元。可使用的字元: REG_EX' +pass_len: '&b【AuthMe】&6您的密碼 超過最大字數 / 小於最小字數。' # Login -usage_log: '&b【AuthMe】&6用法: &c"/login <密碼>"' +usage_log: '&b【AuthMe】&6用法: &c"/login <密碼>"。' wrong_pwd: '&b【AuthMe】&6密碼錯誤!' -login: '&b【AuthMe】&6密碼正確,你已成功登入!' +login: '&b【AuthMe】&6密碼正確,您已成功登入!' login_msg: '&b【AuthMe】&6請使用 &c"/login <密碼>" &6來登入。' -timeout: '&b【AuthMe】&6超過登入時間,請稍後再試一次' +timeout: '&b【AuthMe】&6超過登入時間,請稍後再試一次。' # Errors -unknown_user: '&b【AuthMe】&6這個帳號還沒有註冊過' -# TODO denied_command: '&cIn order to use this command you must be authenticated!' -# TODO denied_chat: '&cIn order to chat you must be authenticated!' -not_logged_in: '&b【AuthMe】&6你還沒有登入!' -# TODO tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +unknown_user: '&b【AuthMe】&6這個帳號還沒有註冊過。' +denied_command: '&b【AuthMe】&c您需要先通過驗證才能使用該命令!' +denied_chat: '&b【AuthMe】&c您需要先通過驗證才能使用聊天系統!' +not_logged_in: '&b【AuthMe】&6您還沒有登入!' +tempban_max_logins: '&b【AuthMe】&c由於您登入失敗次數過多,已暫時被禁止登入。' # TODO: Missing tags %reg_count, %max_acc, %reg_names -max_reg: '&b【AuthMe】&6你的 IP 位置所註冊的帳號數量已經達到最大。' -no_perm: '&b【AuthMe】&6你沒有使用該指令的權限。' +max_reg: '&b【AuthMe】&6您的 IP 位置所註冊的帳號數量已經達到最大。' +no_perm: '&b【AuthMe】&6您沒有使用該指令的權限。' error: '&b【AuthMe】&6發生錯誤,請聯繫管理員' -kick_forvip: '&b【AuthMe】&6你已經被請出。&c原因 : 有 VIP 玩家登入伺服器' +kick_forvip: '&b【AuthMe】&6您已經被請出。&c原因 : 有 VIP 玩家登入伺服器' # AntiBot kick_antibot: '&b【AuthMe】&cAntiBotMod 正在啟用中,請稍後再嘗試登入吧!' @@ -43,10 +43,10 @@ antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!' antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉' # Other messages -unregistered: '&b【AuthMe】&6你已經成功取消註冊。' -# TODO accounts_owned_self: 'You own %count accounts:' -# TODO accounts_owned_other: 'The player %name has %count accounts:' -two_factor_create: '&b【AuthMe - 兩步驗證碼】&b你的登入金鑰為&9「%c%code&9」&b,掃描連結為:&c %url' +unregistered: '&b【AuthMe】&6您已經成功取消註冊。' +accounts_owned_self: '&b【AuthMe】您擁有 %count 個帳號:' +accounts_owned_other: '&b【AuthMe】玩家 %name 擁有 %count 個帳號:' +two_factor_create: '&b【AuthMe - 兩步驗證碼】&b您的登入金鑰為&9「%c%code&9」&b,掃描連結為:&c %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! You have %count tries remaining.' # TODO recovery_tries_exceeded: 'You have exceeded the maximum number attempts to enter the recovery code. Use "/email recovery [email]" to generate a new one.' diff --git a/src/test/java/fr/xephi/authme/api/v3/AuthMeApiTest.java b/src/test/java/fr/xephi/authme/api/v3/AuthMeApiTest.java index 03297abae..433675f9c 100644 --- a/src/test/java/fr/xephi/authme/api/v3/AuthMeApiTest.java +++ b/src/test/java/fr/xephi/authme/api/v3/AuthMeApiTest.java @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collectors; +import java.time.Instant; import static fr.xephi.authme.IsEqualByReflectionMatcher.isEqualTo; import static org.hamcrest.Matchers.contains; @@ -202,7 +203,7 @@ public class AuthMeApiTest { // then assertThat(result, not(nullValue())); - assertThat(result, equalTo(new Date(1501597979))); + assertThat(result, equalTo(new Date(1501597979L))); } @Test @@ -222,6 +223,40 @@ public class AuthMeApiTest { verify(dataSource).getAuth(name); } + @Test + public void shouldGetLastLoginTime() { + // given + String name = "David"; + PlayerAuth auth = PlayerAuth.builder().name(name) + .lastLogin(1501597979L) + .build(); + given(playerCache.getAuth(name)).willReturn(auth); + + // when + Instant result = api.getLastLoginTime(name); + + // then + assertThat(result, not(nullValue())); + assertThat(result, equalTo(Instant.ofEpochMilli(1501597979L))); + } + + @Test + public void shouldHandleNullLastLoginTime() { + // given + String name = "John"; + PlayerAuth auth = PlayerAuth.builder().name(name) + .lastLogin(null) + .build(); + given(dataSource.getAuth(name)).willReturn(auth); + + // when + Instant result = api.getLastLoginTime(name); + + // then + assertThat(result, nullValue()); + verify(dataSource).getAuth(name); + } + @Test public void shouldReturnNullForUnavailablePlayer() { // given diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java index eac5f8fb9..d73219984 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java @@ -15,6 +15,8 @@ import java.util.Arrays; import java.util.Collections; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.containsStringIgnoringCase; +import static org.hamcrest.Matchers.equalToIgnoringCase; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -55,7 +57,7 @@ public class RecentPlayersCommandTest { // then verify(sender).sendMessage(argThat(containsString("Recently logged in players"))); - verify(sender).sendMessage("- Hannah (08:09 AM, 11 Nov with IP 11.11.11.11)"); - verify(sender).sendMessage("- MATT (11:15 PM, 09 Nov with IP 22.11.22.33)"); + verify(sender).sendMessage(argThat(equalToIgnoringCase("- Hannah (08:09 AM, 11 Nov with IP 11.11.11.11)"))); + verify(sender).sendMessage(argThat(equalToIgnoringCase("- MATT (11:15 PM, 09 Nov with IP 22.11.22.33)"))); } } diff --git a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java index 9ca0bc090..416649e05 100644 --- a/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/email/RecoverEmailCommandTest.java @@ -10,6 +10,7 @@ import fr.xephi.authme.datasource.DataSourceResult; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.security.PasswordSecurity; +import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.service.PasswordRecoveryService; import fr.xephi.authme.service.RecoveryCodeService; @@ -22,6 +23,7 @@ import org.mockito.Mock; import java.util.Collections; +import static fr.xephi.authme.service.BukkitServiceTestHelper.setBukkitServiceToRunTaskAsynchronously; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -63,6 +65,9 @@ public class RecoverEmailCommandTest { @Mock private RecoveryCodeService recoveryCodeService; + @Mock + private BukkitService bukkitService; + @BeforeClass public static void initLogger() { TestHelper.setupLogger(); @@ -179,6 +184,7 @@ public class RecoverEmailCommandTest { String code = "a94f37"; given(recoveryCodeService.isRecoveryCodeNeeded()).willReturn(true); given(recoveryCodeService.generateCode(name)).willReturn(code); + setBukkitServiceToRunTaskAsynchronously(bukkitService); // when command.executeCommand(sender, Collections.singletonList(email.toUpperCase())); @@ -201,6 +207,7 @@ public class RecoverEmailCommandTest { String email = "vulture@example.com"; given(dataSource.getEmail(name)).willReturn(DataSourceResult.of(email)); given(recoveryCodeService.isRecoveryCodeNeeded()).willReturn(false); + setBukkitServiceToRunTaskAsynchronously(bukkitService); // when command.executeCommand(sender, Collections.singletonList(email)); diff --git a/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java b/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java index 2b1e311c4..b9ac1cd81 100644 --- a/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java +++ b/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java @@ -107,14 +107,14 @@ public class LimboPersistenceTest { Player player = mock(Player.class); Logger logger = TestHelper.setupLogger(); LimboPersistenceHandler handler = getHandler(); - doThrow(IllegalAccessException.class).when(handler).getLimboPlayer(player); + doThrow(RuntimeException.class).when(handler).getLimboPlayer(player); // when LimboPlayer result = limboPersistence.getLimboPlayer(player); // then assertThat(result, nullValue()); - verify(logger).warning(argThat(containsString("[IllegalAccessException]"))); + verify(logger).warning(argThat(containsString("[RuntimeException]"))); } @Test diff --git a/src/test/java/fr/xephi/authme/security/crypts/CmwCryptTest.java b/src/test/java/fr/xephi/authme/security/crypts/CmwCryptTest.java new file mode 100644 index 000000000..7c6652db1 --- /dev/null +++ b/src/test/java/fr/xephi/authme/security/crypts/CmwCryptTest.java @@ -0,0 +1,15 @@ +package fr.xephi.authme.security.crypts; + +/** + * Test for {@link CmwCrypt}. + */ +public class CmwCryptTest extends AbstractEncryptionMethodTest { + + public CmwCryptTest() { + super(new CmwCrypt(), + "1619d7adc23f4f633f11014d2f22b7d8", // password + "c651798d2d9da38f86654107ae60c86a", // PassWord1 + "1fff869a744700cdb623a403c46e93ea", // &^%te$t?Pw@_ + "6436230e0effff37af79302147319dda"); // âË_3(íù* + } +} diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index 87fc308c1..154137ef4 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -117,12 +117,6 @@ public class UtilsTest { assertThat(Utils.isCollectionEmpty(null), equalTo(true)); } - @Test - public void shouldReturnCoreCount() { - // given / when / then - assertThat(Utils.getCoreCount(), greaterThan(0)); - } - @Test public void shouldLogAndSendWarning() { // given