Built-in Deprecated FlatFile (auths.db) to SQL (authme.sql) converter!
Import your old database from other plugins like Rakamak, xAuth, CrazyLogin, RoyalAuth and vAuth!
####Configuration
-How to Configure Authme
+How to configure Authme
####Email Recovery Dependency
How to configure email recovery system?
####Commands
@@ -125,30 +117,21 @@ You can also create your own translation file and, if you want, you can share it
- [List of all permission nodes](http://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md)
####How To
-- [How to install and set up](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-install-and-initial-configuration/)
- [How to import database from xAuth](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-xauth/)
- [Website integration](http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/)
-- [Click here for an example of the config file](https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml)
- [How to convert from Rakamak](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/)
-- Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
+- Convert between database types (e.g. SQLite to MySQL): /authme converter
-#####GeoIP
-This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com
-
-
-
-#####Donate
-
Do you like our work? Do you want to buy us a coffee? :)
-EUR:
-USD:
-
#####Sponsor
GameHosting.it is leader in Italy as Game Server Provider. With its own DataCenter offers Anti-DDoS solutions at affordable prices. Game Server of Minecraft based on Multicraft are equipped with the latest technology in hardware.
[![GameHosting](http://www.gamehosting.it/images/bn3.png)](http://www.gamehosting.it)
#####Credits
-
Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka
Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex
+
+#####GeoIP License
+This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com
diff --git a/circle.yml b/circle.yml
index 80201e5e8..3359eb2ad 100644
--- a/circle.yml
+++ b/circle.yml
@@ -11,6 +11,8 @@ test:
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-legacy.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS/AuthMe.jar
+ - mkdir -p $CIRCLE_TEST_REPORTS/junit/
+ - find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
notify:
webhooks:
- url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf
diff --git a/docs/commands.md b/docs/commands.md
index 4dd070fd6..b9f68054e 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -1,5 +1,5 @@
-
+
## AuthMe Commands
You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >`
@@ -63,7 +63,8 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
- **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded.
Requires `authme.player.changepassword`
- **/changepassword help** [query]: View detailed help for /changepassword commands.
-- **/email**: The AuthMeReloaded Email command base.
+- **/email**: The AuthMeReloaded email command base.
+- **/email show**: Show your current email address.
- **/email add** <email> <verifyEmail>: Add a new email address to your account.
Requires `authme.player.email.add`
- **/email change** <oldEmail> <newEmail>: Change an email address of your account.
@@ -75,7 +76,6 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
Requires `authme.player.captcha`
- **/captcha help** [query]: View detailed help for /captcha commands.
-
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:08 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:12 CEST 2016
diff --git a/docs/config.md b/docs/config.md
new file mode 100644
index 000000000..212d83a7d
--- /dev/null
+++ b/docs/config.md
@@ -0,0 +1,467 @@
+
+
+
+## AuthMe Configuration
+The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
+with which you can configure various settings. This following is the initial contents of
+the generated config.yml file.
+
+```yml
+
+DataSource:
+ # What type of database do you want to use?
+ # Valid values: sqlite, mysql
+ backend: 'SQLITE'
+ # Enable database caching, should improve database performance
+ caching: true
+ # Database host address
+ mySQLHost: '127.0.0.1'
+ # Database port
+ mySQLPort: '3306'
+ # Username about Database Connection Infos
+ mySQLUsername: 'authme'
+ # Password about Database Connection Infos
+ mySQLPassword: '12345'
+ # Database Name, use with converters or as SQLITE database name
+ mySQLDatabase: 'authme'
+ # Table of the database
+ mySQLTablename: 'authme'
+ # Column of IDs to sort data
+ mySQLColumnId: 'id'
+ # Column for storing or checking players nickname
+ mySQLColumnName: 'username'
+ # Column for storing or checking players RealName
+ mySQLRealName: 'realname'
+ # Column for storing players passwords
+ mySQLColumnPassword: 'password'
+ # Column for storing players emails
+ mySQLColumnEmail: 'email'
+ # Column for storing if a player is logged in or not
+ mySQLColumnLogged: 'isLogged'
+ # Column for storing players ips
+ mySQLColumnIp: 'ip'
+ # Column for storing players lastlogins
+ mySQLColumnLastLogin: 'lastlogin'
+ # Column for storing player LastLocation - X
+ mySQLlastlocX: 'x'
+ # Column for storing player LastLocation - Y
+ mySQLlastlocY: 'y'
+ # Column for storing player LastLocation - Z
+ mySQLlastlocZ: 'z'
+ # Column for storing player LastLocation - World Name
+ mySQLlastlocWorld: 'world'
+ # Overrides the size of the DB Connection Pool, -1 = Auto
+ poolSize: -1
+ExternalBoardOptions:
+ # Column for storing players passwords salts
+ mySQLColumnSalt: ''
+ # Column for storing players groups
+ mySQLColumnGroup: ''
+ # -1 means disabled. If you want that only activated players
+ # can log into your server, you can set here the group number
+ # of unactivated users, needed for some forum/CMS support
+ nonActivedUserGroup: -1
+ # Other MySQL columns where we need to put the username (case-sensitive)
+ mySQLOtherUsernameColumns: []
+ # How much log2 rounds needed in BCrypt (do not change if you do not know what it does)
+ bCryptLog2Round: 10
+ # phpBB table prefix defined during the phpBB installation process
+ phpbbTablePrefix: 'phpbb_'
+ # phpBB activated group ID; 2 is the default registered group defined by phpBB
+ phpbbActivatedGroupId: 2
+ # Wordpress prefix defined during WordPress installation
+ wordpressTablePrefix: 'wp_'
+Converter:
+ Rakamak:
+ # Rakamak file name
+ fileName: 'users.rak'
+ # Rakamak use IP?
+ useIP: false
+ # Rakamak IP file name
+ ipFileName: 'UsersIp.rak'
+ CrazyLogin:
+ # CrazyLogin database file name
+ fileName: 'accounts.db'
+settings:
+ sessions:
+ # Do you want to enable the session feature?
+ # If enabled, when a player authenticates successfully,
+ # his IP and his nickname is saved.
+ # The next time the player joins the server, if his IP
+ # is the same as last time and the timeout hasn't
+ # expired, he will not need to authenticate.
+ enabled: false
+ # After how many minutes should a session expire?
+ # Remember that sessions will end only after the timeout, and
+ # if the player's IP has changed but the timeout hasn't expired,
+ # the player will be kicked from the server due to invalid session
+ timeout: 10
+ # Should the session expire if the player tries to log in with
+ # another IP address?
+ sessionExpireOnIpChange: true
+ # Message language, available languages:
+ # https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md
+ messagesLanguage: 'en'
+ restrictions:
+ # Keeps collisions disabled for logged players
+ # Works only with MC 1.9
+ keepCollisionsDisabled: false
+ # Can not authenticated players chat?
+ # Keep in mind that this feature also blocks all commands not
+ # listed in the list below.
+ allowChat: false
+ # Hide the chat log from players who are not authenticated?
+ hideChat: false
+ # Allowed commands for unauthenticated players
+ allowCommands:
+ - '/login'
+ - '/register'
+ - '/l'
+ - '/reg'
+ - '/email'
+ - '/captcha'
+ # Max number of allowed registrations per IP
+ # The value 0 means an unlimited number of registrations!
+ maxRegPerIp: 1
+ # Minimum allowed username length
+ minNicknameLength: 3
+ # Maximum allowed username length
+ maxNicknameLength: 16
+ # When this setting is enabled, online players can't be kicked out
+ # due to "Logged in from another Location"
+ # This setting will prevent potential security exploits.
+ ForceSingleSession: true
+ ForceSpawnLocOnJoin:
+ # If enabled, every player that spawn in one of the world listed in
+ # "ForceSpawnLocOnJoin.worlds" will be teleported to the spawnpoint after successful
+ # authentication. The quit location of the player will be overwritten.
+ # This is different from "teleportUnAuthedToSpawn" that teleport player
+ # to the spawnpoint on join.
+ enabled: false
+ # WorldNames where we need to force the spawn location
+ # Case-sensitive!
+ worlds:
+ - 'world'
+ - 'world_nether'
+ - 'world_the_end'
+ # This option will save the quit location of the players.
+ SaveQuitLocation: false
+ # To activate the restricted user feature you need
+ # to enable this option and configure the AllowedRestrictedUser field.
+ AllowRestrictedUser: false
+ # The restricted user feature will kick players listed below
+ # if they don't match the defined IP address. Names are case-insensitive.
+ # Example:
+ # AllowedRestrictedUser:
+ # - playername;127.0.0.1
+ AllowedRestrictedUser: []
+ # Should unregistered players be kicked immediately?
+ kickNonRegistered: false
+ # Should players be kicked on wrong password?
+ kickOnWrongPassword: false
+ # Should not logged in players be teleported to the spawn?
+ # After the authentication they will be teleported back to
+ # their normal position.
+ teleportUnAuthedToSpawn: false
+ # Can unregistered players walk around?
+ allowMovement: false
+ # Should not authenticated players have speed = 0?
+ # This will reset the fly/walk speed to default value after the login.
+ removeSpeed: true
+ # After how many seconds should players who fail to login or register
+ # be kicked? Set to 0 to disable.
+ timeout: 30
+ # Regex syntax of allowed characters in the player name.
+ allowedNicknameCharacters: '[a-zA-Z0-9_]*'
+ # How far can unregistered players walk?
+ # Set to 0 for unlimited radius
+ allowedMovementRadius: 100
+ # Enable double check of password when you register
+ # when it's true, registration requires that kind of command:
+ # /register
+ enablePasswordConfirmation: true
+ # Should we protect the player inventory before logging in? Requires ProtocolLib.
+ ProtectInventoryBeforeLogIn: true
+ # Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.
+ DenyTabCompleteBeforeLogin: true
+ # Should we display all other accounts from a player when he joins?
+ # permission: /authme.admin.accounts
+ displayOtherAccounts: true
+ # Ban ip when the ip is not the ip registered in database
+ banUnsafedIP: false
+ # Spawn priority; values: authme, essentials, multiverse, default
+ spawnPriority: 'authme,essentials,multiverse,default'
+ # Maximum Login authorized by IP
+ maxLoginPerIp: 0
+ # Maximum Join authorized by IP
+ maxJoinPerIp: 0
+ # AuthMe will NEVER teleport players if set to true!
+ noTeleport: false
+ # Regex syntax for allowed chars in passwords
+ allowedPasswordCharacters: '[\x21-\x7E]*'
+ # Threshold of the other accounts command, a value less than 2 means disabled.
+ otherAccountsCmdThreshold: 0
+ # Command to run when a user has more accounts than the configured threshold.
+ # Available variables: %playername%, %playerip%
+ otherAccountsCmd: 'say The player %playername% with ip %playerip% has multiple accounts!'
+ # Log level: INFO, FINE, DEBUG. Use INFO for general messages,
+ # FINE for some additional detailed ones (like password failed),
+ # and DEBUG for debugging
+ logLevel: 'FINE'
+ # By default we schedule async tasks when talking to the database. If you want
+ # typical communication with the database to happen synchronously, set this to false
+ useAsyncTasks: true
+ GameMode:
+ # Force survival gamemode when player joins?
+ ForceSurvivalMode: false
+ unrestrictions:
+ # Below you can list all account names that AuthMe will ignore
+ # for registration or login. Configure it at your own risk!!
+ # This option adds compatibility with BuildCraft and some other mods.
+ # It is case-insensitive! Example:
+ # UnrestrictedName:
+ # - 'npcPlayer'
+ # - 'npcPlayer2'
+ UnrestrictedName: []
+ security:
+ # Minimum length of password
+ minPasswordLength: 5
+ # Maximum length of password
+ passwordMaxLength: 30
+ # This is a very important option: every time a player joins the server,
+ # if they are registered, AuthMe will switch him to unLoggedInGroup.
+ # This should prevent all major exploits.
+ # You can set up your permission plugin with this special group to have no permissions,
+ # or only permission to chat (or permission to send private messages etc.).
+ # The better way is to set up this group with few permissions, so if a player
+ # tries to exploit an account they can do only what you've defined for the group.
+ # After, a logged in player will be moved to his correct permissions group!
+ # Please note that the group name is case-sensitive, so 'admin' is different from 'Admin'
+ # Otherwise your group will be wiped and the player will join in the default group []!
+ # Example unLoggedinGroup: NotLogged
+ unLoggedinGroup: 'unLoggedinGroup'
+ # Possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,
+ # MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,
+ # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only)
+ passwordHash: 'SHA256'
+ # Salt length for the SALTED2MD5 MD5(MD5(password)+salt)
+ doubleMD5SaltLength: 8
+ # If a password check fails, AuthMe will also try to check with the following hash methods.
+ # Use this setting when you change from one hash method to another.
+ # AuthMe will update the password to the new hash. Example:
+ # legacyHashes:
+ # - 'SHA1'
+ legacyHashes: []
+ # Prevent unsafe passwords from being used; put them in lowercase!
+ # You should always set 'help' as unsafePassword due to possible conflicts.
+ # unsafePasswords:
+ # - '123456'
+ # - 'password'
+ # - 'help'
+ unsafePasswords:
+ - '123456'
+ - 'password'
+ - 'qwerty'
+ - '12345'
+ - '54321'
+ - '123456789'
+ - 'help'
+ registration:
+ # Enable registration on the server?
+ enabled: true
+ # Send every X seconds a message to a player to
+ # remind him that he has to login/register
+ messageInterval: 5
+ # Only registered and logged in players can play.
+ # See restrictions for exceptions
+ force: true
+ # Do we replace password registration by an email registration method?
+ enableEmailRegistrationSystem: false
+ # Enable double check of email when you register
+ # when it's true, registration requires that kind of command:
+ # /register
+ doubleEmailCheck: false
+ # Do we force kick a player after a successful registration?
+ # Do not use with login feature below
+ forceKickAfterRegister: false
+ # Does AuthMe need to enforce a /login after a successful registration?
+ forceLoginAfterRegister: false
+ # Force these commands after /login, without any '/', use %p to replace with player name
+ forceCommands: []
+ # Force these commands after /login as service console, without any '/'.
+ # Use %p to replace with player name
+ forceCommandsAsConsole: []
+ # Force these commands after /register, without any '/', use %p to replace with player name
+ forceRegisterCommands: []
+ # Force these commands after /register as a server console, without any '/'.
+ # Use %p to replace with player name
+ forceRegisterCommandsAsConsole: []
+ # Enable to display the welcome message (welcome.txt) after a login
+ # You can use colors in this welcome.txt + some replaced strings:
+ # {PLAYER}: player name, {ONLINE}: display number of online players,
+ # {MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged,
+ # {WORLD}: player current world, {SERVER}: server name
+ # {VERSION}: get current bukkit version, {COUNTRY}: player country
+ useWelcomeMessage: true
+ # Broadcast the welcome message to the server or only to the player?
+ # set true for server or false for player
+ broadcastWelcomeMessage: false
+ # Should we delay the join message and display it once the player has logged in?
+ delayJoinMessage: false
+ # Should we remove the leave messages of unlogged users?
+ removeUnloggedLeaveMessage: false
+ # Should we remove join messages altogether?
+ removeJoinMessage: false
+ # Should we remove leave messages altogether?
+ removeLeaveMessage: false
+ # Do we need to add potion effect Blinding before login/reigster?
+ applyBlindEffect: false
+ # Do we need to prevent people to login with another case?
+ # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
+ preventOtherCase: false
+permission:
+ # Take care with this option; if you want
+ # to use group switching of AuthMe
+ # for unloggedIn players, set this setting to true.
+ # Default is false.
+ EnablePermissionCheck: false
+Email:
+ # Email SMTP server host
+ mailSMTP: 'smtp.gmail.com'
+ # Email SMTP server port
+ mailPort: 465
+ # Email account which sends the mails
+ mailAccount: ''
+ # Email account password
+ mailPassword: ''
+ # Custom sender name, replacing the mailAccount name in the email
+ mailSenderName: ''
+ # Recovery password length
+ RecoveryPasswordLength: 8
+ # Mail Subject
+ mailSubject: 'Your new AuthMe password'
+ # Like maxRegPerIP but with email
+ maxRegPerEmail: 1
+ # Recall players to add an email?
+ recallPlayers: false
+ # Delay in minute for the recall scheduler
+ delayRecall: 5
+ # Blacklist these domains for emails
+ emailBlacklisted:
+ - '10minutemail.com'
+ # Whitelist ONLY these domains for emails
+ emailWhitelisted: []
+ # Send the new password drawn in an image?
+ generateImage: false
+ # The OAuth2 token
+ emailOauth2Token: ''
+Hooks:
+ # Do we need to hook with multiverse for spawn checking?
+ multiverse: true
+ # Do we need to hook with BungeeCord?
+ bungeecord: false
+ # Send player to this BungeeCord server after register/login
+ sendPlayerTo: ''
+ # Do we need to disable Essentials SocialSpy on join?
+ disableSocialSpy: true
+ # Do we need to force /motd Essentials command on join?
+ useEssentialsMotd: false
+GroupOptions:
+ # Unregistered permission group
+ UnregisteredPlayerGroup: ''
+ # Registered permission group
+ RegisteredPlayerGroup: ''
+Protection:
+ # Enable some servers protection (country based login, antibot)
+ enableProtection: false
+ # Apply the protection also to registered usernames
+ enableProtectionRegistered: true
+ # Countries allowed to join the server and register. For country codes, see
+ # http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/
+ # PLEASE USE QUOTES!
+ countries:
+ - 'US'
+ - 'GB'
+ # Countries not allowed to join the server and register
+ # PLEASE USE QUOTES!
+ countriesBlacklist:
+ - 'A1'
+ # Do we need to enable automatic antibot system?
+ enableAntiBot: true
+ # The interval in seconds
+ antiBotInterval: 5
+ # Max number of players allowed to login in the interval
+ # before the AntiBot system is enabled automatically
+ antiBotSensibility: 10
+ # Duration in minutes of the antibot automatic system
+ antiBotDuration: 10
+ # Delay in seconds before the antibot activation
+ antiBotDelay: 60
+Purge:
+ # If enabled, AuthMe automatically purges old, unused accounts
+ useAutoPurge: false
+ # Number of days after which an account should be purged
+ daysBeforeRemovePlayer: 60
+ # Do we need to remove the player.dat file during purge process?
+ removePlayerDat: false
+ # Do we need to remove the Essentials/userdata/player.yml file during purge process?
+ removeEssentialsFile: false
+ # World where are players.dat stores
+ defaultWorld: 'world'
+ # Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?
+ removeLimitedCreativesInventories: false
+ # Do we need to remove the AntiXRayData/PlayerData/player file during purge process?
+ removeAntiXRayFile: false
+ # Do we need to remove permissions?
+ removePermissions: false
+Security:
+ SQLProblem:
+ # Stop the server if we can't contact the sql database
+ # Take care with this, if you set this to false,
+ # AuthMe will automatically disable and the server won't be protected!
+ stopServer: true
+ console:
+ # Remove passwords from console?
+ removePassword: true
+ # Copy AuthMe log output in a separate file as well?
+ logConsole: true
+ captcha:
+ # Enable captcha when a player uses wrong password too many times
+ useCaptcha: false
+ # Max allowed tries before a captcha is required
+ maxLoginTry: 5
+ # Captcha length
+ captchaLength: 5
+ tempban:
+ # Tempban a user's IP address if they enter the wrong password too many times
+ enableTempban: false
+ # How many times a user can attempt to login before their IP being tempbanned
+ maxLoginTries: 10
+ # The length of time a IP address will be tempbanned in minutes
+ # Default: 480 minutes, or 8 hours
+ tempbanLength: 480
+ # How many minutes before resetting the count for failed logins by IP and username
+ # Default: 480 minutes (8 hours)
+ minutesBeforeCounterReset: 480
+ recoveryCode:
+ # Number of characters a recovery code should have (0 to disable)
+ length: 8
+ # How many hours is a recovery code valid for?
+ validForHours: 4
+BackupSystem:
+ # Enable or disable automatic backup
+ ActivateBackup: false
+ # Set backup at every start of server
+ OnServerStart: false
+ # Set backup at every stop of server
+ OnServerStop: true
+ # Windows only mysql installation Path
+ MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\'
+```
+
+To change settings on a running server, save your changes to config.yml and use
+`/authme reload`.
+
+---
+
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Nov 13 13:34:49 CET 2016
diff --git a/docs/hash_algorithms.md b/docs/hash_algorithms.md
index e7fd0ae36..02bcafe6f 100644
--- a/docs/hash_algorithms.md
+++ b/docs/hash_algorithms.md
@@ -1,5 +1,5 @@
-
+
## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely.
@@ -13,11 +13,11 @@ CRAZYCRYPT1 | Do not use | 128 | | | Username | |
DOUBLEMD5 | Do not use | 32 | | | None | |
IPB3 | Acceptable | 32 | | | Text | 5 | Y
IPB4 | Does not work | 60 | | | Text | 22 | Y
-JOOMLA | Recommended | 65 | | | Text | 32 |
+JOOMLA | Acceptable | 65 | | | Text | 32 |
MD5 | Do not use | 32 | | | None | |
MD5VB | Acceptable | 56 | | | Text | 16 |
MYBB | Acceptable | 32 | | | Text | 8 | Y
-PBKDF2 | Does not work | 332 | | | Text | 12 |
+PBKDF2 | Recommended | 165 | | | Text | 16 |
PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 |
PHPBB | Acceptable | 34 | | | Text | 16 |
PHPFUSION | Do not use | 64 | Y | | | | Y
@@ -82,4 +82,4 @@ or bad.
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Oct 01 23:42:20 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Fri Nov 25 15:48:35 CET 2016
diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md
index 60d39a15c..fb6408206 100644
--- a/docs/permission_nodes.md
+++ b/docs/permission_nodes.md
@@ -1,5 +1,5 @@
-
+
## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds.
@@ -38,15 +38,15 @@ The following are the permission nodes that are currently supported by the lates
- **authme.player.email** – Grants all email permissions.
- **authme.player.email.add** – Command permission to add an email address.
- **authme.player.email.change** – Command permission to change the email address.
-- **authme.player.email.recover** – Command permission to recover an account using it's email address.
+- **authme.player.email.recover** – Command permission to recover an account using its email address.
- **authme.player.login** – Command permission to login.
- **authme.player.logout** – Command permission to logout.
- **authme.player.register** – Command permission to register.
- **authme.player.seeownaccounts** – Permission to use to see own other accounts.
- **authme.player.unregister** – Command permission to unregister.
-- **authme.vip** – Permission node to identify VIP users.
+- **authme.vip** – When the server is full and someone with this permission joins the server, someone will be kicked.
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:10 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 15:38:58 CEST 2016
diff --git a/docs/translations.md b/docs/translations.md
index c261bb8f6..a96f2cf61 100644
--- a/docs/translations.md
+++ b/docs/translations.md
@@ -1,5 +1,5 @@
-
+
# AuthMe Translations
The following translations are available in AuthMe. Set `messagesLanguage` to the language code
@@ -8,32 +8,34 @@ in your config.yml to use the language, or use another language code to start a
Code | Language | Translated |
---- | -------- | ---------: | ------
[en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% |
-[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 73% |
+[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 71% |
[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% |
-[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 91% |
-[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 97% |
+[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 88% |
+[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 95% |
[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% |
-[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 66% |
-[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 70% |
-[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 97% |
-[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 74% |
+[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 64% |
+[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 68% |
+[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 95% |
+[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 72% |
[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% |
-[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 74% |
+[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 72% |
[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% |
-[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 76% |
-[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 57% |
-[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 80% |
-[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 95% |
-[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 91% |
-[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 97% |
-[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 50% |
-[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 85% |
-[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 97% |
-[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 85% |
-[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 85% |
-[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 85% |
-[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 85% |
+[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 74% |
+[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 55% |
+[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 78% |
+[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 100% |
+[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 88% |
+[ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 100% |
+[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 100% |
+[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 49% |
+[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 83% |
+[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 95% |
+[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 83% |
+[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 83% |
+[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 83% |
+[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 83% |
+
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 09 09:42:48 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Dec 11 08:16:38 CET 2016
diff --git a/pom.xml b/pom.xml
index 60fb7c40d..52c17b68b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,7 +62,7 @@
Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008
- 1.10.2-R0.1-SNAPSHOT
+ 1.11-R0.1-SNAPSHOT
@@ -196,7 +196,7 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.5.1
+ 3.6.0${project.jdkVersion}
@@ -268,6 +268,10 @@
net.ricecode.similarityfr.xephi.authme.libs.ricecode.similarity
+
+ de.rtner
+ fr.xephi.authme.libs.de.rtner
+ javax.injectfr.xephi.authme.libs.javax.inject
@@ -319,6 +323,10 @@
net.ricecode.similarityfr.xephi.authme.libs.ricecode.similarity
+
+ de.rtner
+ fr.xephi.authme.libs.de.rtner
+ javax.injectfr.xephi.authme.libs.javax.inject
@@ -524,6 +532,13 @@
true
+
+
+ de.rtner
+ PBKDF2
+ 1.1.2
+
+
@@ -873,7 +888,7 @@
com.github.authmeconfigme
- 0.2
+ 0.2.1compiletrue
@@ -904,7 +919,7 @@
org.mockitomockito-coretest
- 2.0.5-beta
+ 2.2.27hamcrest-core
@@ -917,13 +932,13 @@
org.xerialsqlite-jdbc
- 3.8.11.2
+ 3.15.1testcom.h2databaseh2
- 1.4.192
+ 1.4.193test
diff --git a/samples/website_integration/AuthMeController.php b/samples/website_integration/AuthMeController.php
index 66fe03b4a..f67cf0608 100644
--- a/samples/website_integration/AuthMeController.php
+++ b/samples/website_integration/AuthMeController.php
@@ -109,7 +109,6 @@ abstract class AuthMeController {
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/
private function getHashFromDatabase($username) {
- // Add here your database host, username, password and database name
$mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');
diff --git a/samples/website_integration/Pbkdf2.php b/samples/website_integration/Pbkdf2.php
new file mode 100644
index 000000000..456c004fc
--- /dev/null
+++ b/samples/website_integration/Pbkdf2.php
@@ -0,0 +1,53 @@
+CHARS = self::initCharRange();
+ }
+
+ protected function isValidPassword($password, $hash) {
+ // hash := pbkdf2_sha256$iterations$salt$hash
+ $parts = explode('$', $hash);
+ return count($parts) === 4 && $hash === $this->computeHash($parts[1], $parts[2], $password);
+ }
+
+ protected function hash($password) {
+ $salt = $this->generateSalt();
+ return $this->computeHash(self::NUMBER_OF_ITERATIONS, $salt, $password);
+ }
+
+ private function computeHash($iterations, $salt, $password) {
+ return 'pbkdf2_sha256$' . self::NUMBER_OF_ITERATIONS . '$' . $salt
+ . '$' . hash_pbkdf2('sha256', $password, $salt, self::NUMBER_OF_ITERATIONS, 64, false);
+ }
+
+ /**
+ * @return string randomly generated salt
+ */
+ private function generateSalt() {
+ $maxCharIndex = count($this->CHARS) - 1;
+ $salt = '';
+ for ($i = 0; $i < self::SALT_LENGTH; ++$i) {
+ $salt .= $this->CHARS[mt_rand(0, $maxCharIndex)];
+ }
+ return $salt;
+ }
+
+ private static function initCharRange() {
+ return array_merge(range('0', '9'), range('a', 'f'));
+ }
+}
diff --git a/samples/website_integration/Sha256.php b/samples/website_integration/Sha256.php
index 815abe59a..80c0588fe 100644
--- a/samples/website_integration/Sha256.php
+++ b/samples/website_integration/Sha256.php
@@ -15,7 +15,7 @@ class Sha256 extends AuthMeController {
const SALT_LENGTH = 16;
public function __construct() {
- $this->CHARS = self::initRandomChars();
+ $this->CHARS = self::initCharRange();
}
protected function isValidPassword($password, $hash) {
@@ -41,7 +41,7 @@ class Sha256 extends AuthMeController {
return $salt;
}
- private static function initRandomChars() {
+ private static function initCharRange() {
return array_merge(range('0', '9'), range('a', 'f'));
}
diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java
index b52caf32e..74a986543 100644
--- a/src/main/java/fr/xephi/authme/AuthMe.java
+++ b/src/main/java/fr/xephi/authme/AuthMe.java
@@ -5,44 +5,45 @@ import ch.jalu.injector.InjectorBuilder;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.api.API;
import fr.xephi.authme.api.NewAPI;
-import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.command.CommandHandler;
+import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder;
-import fr.xephi.authme.initialization.Initializer;
-import fr.xephi.authme.initialization.MetricsManager;
+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.BlockListener;
import fr.xephi.authme.listener.EntityListener;
import fr.xephi.authme.listener.PlayerListener;
+import fr.xephi.authme.listener.PlayerListener111;
import fr.xephi.authme.listener.PlayerListener16;
import fr.xephi.authme.listener.PlayerListener18;
import fr.xephi.authme.listener.PlayerListener19;
import fr.xephi.authme.listener.ServerListener;
-import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PermissionsSystemType;
import fr.xephi.authme.security.crypts.SHA256;
import fr.xephi.authme.service.BackupService;
+import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService;
+import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.CleanupTask;
import fr.xephi.authme.task.purge.PurgeService;
-import fr.xephi.authme.service.BukkitService;
-import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
-import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler;
import java.io.File;
@@ -60,7 +61,7 @@ public class AuthMe extends JavaPlugin {
private static final String LOG_FILENAME = "authme.log";
private static final int CLEANUP_INTERVAL = 5 * TICKS_PER_MINUTE;
- // Default version and build number values;
+ // Default version and build number values
private static String pluginVersion = "N/D";
private static String pluginBuildNumber = "Unknown";
@@ -68,7 +69,6 @@ public class AuthMe extends JavaPlugin {
private CommandHandler commandHandler;
private PermissionsManager permsMan;
private Settings settings;
- private Messages messages;
private DataSource database;
private BukkitService bukkitService;
private Injector injector;
@@ -86,9 +86,8 @@ public class AuthMe extends JavaPlugin {
*/
@VisibleForTesting
@SuppressWarnings("deprecation") // the super constructor is deprecated to mark it for unit testing only
- protected AuthMe(final PluginLoader loader, final Server server, final PluginDescriptionFile description,
- final File dataFolder, final File file) {
- super(loader, server, description, dataFolder, file);
+ protected AuthMe(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
+ super(loader, description, dataFolder, file);
}
/**
@@ -133,7 +132,7 @@ public class AuthMe extends JavaPlugin {
@Override
public void onEnable() {
// Load the plugin version data from the plugin description file
- loadPluginInfo();
+ loadPluginInfo(getDescription().getVersion());
// Initialize the plugin
try {
@@ -156,7 +155,7 @@ public class AuthMe extends JavaPlugin {
new BackupService(this, settings).doBackup(BackupService.BackupCause.START);
// Set up Metrics
- MetricsManager.sendMetrics(this, settings);
+ OnStartupTasks.sendMetrics(this, settings);
// Sponsor messages
ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt.");
@@ -176,9 +175,10 @@ public class AuthMe extends JavaPlugin {
/**
* 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 void loadPluginInfo() {
- String versionRaw = this.getDescription().getVersion();
+ private static void loadPluginInfo(String versionRaw) {
int index = versionRaw.lastIndexOf("-");
if (index != -1) {
pluginVersion = versionRaw.substring(0, index);
@@ -191,10 +191,8 @@ public class AuthMe extends JavaPlugin {
/**
* Initialize the plugin and all the services.
- *
- * @throws Exception if the initialization fails
*/
- private void initialize() throws Exception {
+ private void initialize() {
// Set the Logger instance and log file path
ConsoleLogger.setLogger(getLogger());
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
@@ -202,40 +200,30 @@ public class AuthMe extends JavaPlugin {
// Create plugin folder
getDataFolder().mkdir();
- // Load settings and set up the console and console filter
- settings = Initializer.createSettings(this);
- bukkitService = new BukkitService(this, settings);
- Initializer initializer = new Initializer(this, bukkitService);
-
- ConsoleLogger.setLoggingOptions(settings);
- initializer.setupConsoleFilter(settings, getLogger());
-
- // Connect to the database and set up tables
- database = initializer.setupDatabase(settings);
-
- // Convert deprecated PLAINTEXT hash entries
- MigrationService.changePlainTextToSha256(settings, database, new SHA256());
-
- // Injector initialization
+ // Create injector, provide elements from the Bukkit environment and register providers
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
-
- // Register elements of the Bukkit / JavaPlugin environment
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);
- // Register elements we instantiate manually
- injector.register(Settings.class, settings);
- injector.register(DataSource.class, database);
- injector.register(BukkitService.class, bukkitService);
+ // Get settings and set up logger
+ settings = injector.getSingleton(Settings.class);
+ ConsoleLogger.setLoggingOptions(settings);
+ OnStartupTasks.setupConsoleFilter(settings, getLogger());
+ // Set all service fields on the AuthMe class
instantiateServices(injector);
+ // Convert deprecated PLAINTEXT hash entries
+ MigrationService.changePlainTextToSha256(settings, database, new SHA256());
+
// TODO: does this still make sense? -sgdc3
// If the server is empty (fresh start) just set all the players as unlogged
- if (bukkitService.getOnlinePlayers().size() == 0) {
+ if (bukkitService.getOnlinePlayers().isEmpty()) {
database.purgeLogged();
}
@@ -243,7 +231,8 @@ public class AuthMe extends JavaPlugin {
registerEventListeners(injector);
// Start Email recall task if needed
- initializer.scheduleRecallEmailTask(settings, database, messages);
+ OnStartupTasks onStartupTasks = injector.newInstance(OnStartupTasks.class);
+ onStartupTasks.scheduleRecallEmailTask();
}
/**
@@ -256,7 +245,7 @@ public class AuthMe extends JavaPlugin {
playerCache = PlayerCache.getInstance();
injector.register(PlayerCache.class, playerCache);
- messages = injector.getSingleton(Messages.class);
+ database = injector.getSingleton(DataSource.class);
permsMan = injector.getSingleton(PermissionsManager.class);
bukkitService = injector.getSingleton(BukkitService.class);
commandHandler = injector.getSingleton(CommandHandler.class);
@@ -312,6 +301,11 @@ public class AuthMe extends JavaPlugin {
if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) {
pluginManager.registerEvents(injector.getSingleton(PlayerListener19.class), this);
}
+
+ // Register listener for 1.11 events if available
+ if (isClassLoaded("org.bukkit.event.entity.EntityAirChangeEvent")) {
+ pluginManager.registerEvents(injector.getSingleton(PlayerListener111.class), this);
+ }
}
/**
@@ -343,10 +337,7 @@ public class AuthMe extends JavaPlugin {
}
// Wait for tasks and close data source
- new Thread(
- new TaskCloser(this, database),
- "AuthMe-DataSource#close"
- ).start();
+ new TaskCloser(this, database).run();
// Disabled correctly
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java
index 7fa027882..d05fbe6b9 100644
--- a/src/main/java/fr/xephi/authme/api/API.java
+++ b/src/main/java/fr/xephi/authme/api/API.java
@@ -19,12 +19,13 @@ import javax.inject.Inject;
/**
* Deprecated API of AuthMe. Please use {@link NewAPI} instead.
+ *
+ * @deprecated Use {@link NewAPI}
*/
@Deprecated
public class API {
- public static final String newline = System.getProperty("line.separator");
- public static AuthMe instance;
+ private static AuthMe instance;
private static DataSource dataSource;
private static PasswordSecurity passwordSecurity;
private static Management management;
@@ -83,28 +84,17 @@ public class API {
}
public static Location getLastLocation(Player player) {
- try {
- PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
+ PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
- if (auth != null) {
- Location loc = new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
- return loc;
- } else {
- return null;
- }
-
- } catch (NullPointerException ex) {
- return null;
+ if (auth != null) {
+ return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
}
+ return null;
}
- public static void setPlayerInventory(Player player, ItemStack[] content,
- ItemStack[] armor) {
- try {
- player.getInventory().setContents(content);
- player.getInventory().setArmorContents(armor);
- } catch (NullPointerException ignored) {
- }
+ public static void setPlayerInventory(Player player, ItemStack[] content, ItemStack[] armor) {
+ player.getInventory().setContents(content);
+ player.getInventory().setArmorContents(armor);
}
/**
diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java
index 5805e4afd..82a2483bc 100644
--- a/src/main/java/fr/xephi/authme/api/NewAPI.java
+++ b/src/main/java/fr/xephi/authme/api/NewAPI.java
@@ -25,8 +25,8 @@ import java.util.List;
*/
public class NewAPI {
- public static NewAPI singleton;
- public final AuthMe plugin;
+ private static NewAPI singleton;
+ private final AuthMe plugin;
private final PluginHookService pluginHookService;
private final DataSource dataSource;
private final PasswordSecurity passwordSecurity;
diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java
index e36664929..8e2b1bdc1 100644
--- a/src/main/java/fr/xephi/authme/command/CommandMapper.java
+++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java
@@ -87,10 +87,10 @@ public class CommandMapper {
return classes;
}
- private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List parts) {
+ private static FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List parts) {
// Return the base command with incorrect arg count error if we only have one part
if (parts.size() <= 1) {
- return new FoundCommandResult(base, parts, new ArrayList(), 0.0, INCORRECT_ARGUMENTS);
+ return new FoundCommandResult(base, parts, new ArrayList<>(), 0.0, INCORRECT_ARGUMENTS);
}
final String childLabel = parts.get(1);
@@ -115,7 +115,7 @@ public class CommandMapper {
final int partsSize = parts.size();
List labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize));
List arguments = (labels.size() == partsSize)
- ? new ArrayList()
+ ? new ArrayList<>()
: parts.subList(labels.size(), partsSize);
return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status);
@@ -141,7 +141,7 @@ public class CommandMapper {
*
* @return A command if there was a complete match (including proper argument count), null otherwise
*/
- private CommandDescription getSuitableChild(CommandDescription baseCommand, List parts) {
+ private static CommandDescription getSuitableChild(CommandDescription baseCommand, List parts) {
if (CollectionUtils.isEmpty(parts)) {
return null;
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java
deleted file mode 100644
index bb8bbeca4..000000000
--- a/src/main/java/fr/xephi/authme/command/CommandService.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package fr.xephi.authme.command;
-
-import com.github.authme.configme.properties.Property;
-import fr.xephi.authme.message.MessageKey;
-import fr.xephi.authme.message.Messages;
-import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.service.ValidationService;
-import org.bukkit.command.CommandSender;
-
-import javax.inject.Inject;
-
-/**
- * Service for implementations of {@link ExecutableCommand} to execute some common tasks.
- * This service basically wraps calls, forwarding them to other classes.
- */
-public class CommandService {
-
- @Inject
- private Messages messages;
- @Inject
- private Settings settings;
- @Inject
- private ValidationService validationService;
-
- /**
- * Send a message to a player.
- *
- * @param sender The command sender to send the message to
- * @param messageKey The message key to send
- */
- public void send(CommandSender sender, MessageKey messageKey) {
- messages.send(sender, messageKey);
- }
-
- /**
- * Send a message to a player.
- *
- * @param sender The command sender to send the message to
- * @param messageKey The message key to send
- * @param replacements The replacement arguments for the message key's tags
- */
- public void send(CommandSender sender, MessageKey messageKey, String... replacements) {
- messages.send(sender, messageKey, replacements);
- }
-
- /**
- * Retrieve a message by its message key.
- *
- * @param key The message to retrieve
- * @return The message
- */
- public String[] retrieveMessage(MessageKey key) {
- return messages.retrieve(key);
- }
-
- /**
- * Retrieve a message as a single String by its message key.
- *
- * @param key The message to retrieve
- * @return The message
- */
- public String retrieveSingle(MessageKey key) {
- return messages.retrieveSingle(key);
- }
-
- /**
- * Retrieve the given property's value.
- *
- * @param property The property to retrieve
- * @param The type of the property
- * @return The property's value
- */
- public T getProperty(Property property) {
- return settings.getProperty(property);
- }
-
- /**
- * Return the settings manager.
- *
- * @return The settings manager
- */
- public Settings getSettings() {
- return settings;
- }
-
- public boolean validateEmail(String email) {
- return validationService.validateEmail(email);
- }
-
- public boolean isEmailFreeForRegistration(String email, CommandSender sender) {
- return validationService.isEmailFreeForRegistration(email, sender);
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
index f3248b565..073655746 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
@@ -1,11 +1,11 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
+import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -23,7 +23,7 @@ public class AccountsCommand implements ExecutableCommand {
private BukkitService bukkitService;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(final CommandSender sender, List arguments) {
@@ -50,13 +50,13 @@ public class AccountsCommand implements ExecutableCommand {
public void run() {
PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase());
if (auth == null) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
List accountList = dataSource.getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) {
- commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
+ commonService.send(sender, MessageKey.USER_NOT_REGISTERED);
} else if (accountList.size() == 1) {
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
} else {
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
index 9842b9f89..d3d975b29 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java
@@ -1,15 +1,15 @@
package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.command.CommandService;
-import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender;
@@ -38,7 +38,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
private ValidationService validationService;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(final CommandSender sender, List arguments) {
@@ -49,38 +49,45 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
// Validate the password
ValidationResult validationResult = validationService.validatePassword(playerPass, playerName);
if (validationResult.hasError()) {
- commandService.send(sender, validationResult.getMessageKey(), validationResult.getArgs());
+ commonService.send(sender, validationResult.getMessageKey(), validationResult.getArgs());
return;
}
// Set the password
- final String playerNameLowerCase = playerName.toLowerCase();
- bukkitService.runTaskOptionallyAsync(new Runnable() {
+ bukkitService.runTaskOptionallyAsync(() -> changePassword(playerName.toLowerCase(), playerPass, sender));
+ }
- @Override
- public void run() {
- PlayerAuth auth = null;
- if (playerCache.isAuthenticated(playerNameLowerCase)) {
- auth = playerCache.getAuth(playerNameLowerCase);
- } else if (dataSource.isAuthAvailable(playerNameLowerCase)) {
- auth = dataSource.getAuth(playerNameLowerCase);
- }
- if (auth == null) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
- return;
- }
+ /**
+ * Changes the password of the given player to the given password.
+ *
+ * @param nameLowercase the name of the player
+ * @param password the password to set
+ * @param sender the sender initiating the password change
+ */
+ private void changePassword(String nameLowercase, String password, CommandSender sender) {
+ PlayerAuth auth = getAuth(nameLowercase);
+ if (auth == null) {
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
+ return;
+ }
- HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase);
- auth.setPassword(hashedPassword);
+ HashedPassword hashedPassword = passwordSecurity.computeHash(password, nameLowercase);
+ auth.setPassword(hashedPassword);
- if (dataSource.updatePassword(auth)) {
- commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
- ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase);
- } else {
- commandService.send(sender, MessageKey.ERROR);
- }
- }
+ if (dataSource.updatePassword(auth)) {
+ commonService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
+ ConsoleLogger.info(sender.getName() + " changed password of " + nameLowercase);
+ } else {
+ commonService.send(sender, MessageKey.ERROR);
+ }
+ }
- });
+ private PlayerAuth getAuth(String nameLowercase) {
+ if (playerCache.isAuthenticated(nameLowercase)) {
+ return playerCache.getAuth(nameLowercase);
+ } else if (dataSource.isAuthAvailable(nameLowercase)) {
+ return dataSource.getAuth(nameLowercase);
+ }
+ return null;
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
index 0cbadf2f0..efa27ff09 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
@@ -4,7 +4,6 @@ import ch.jalu.injector.Injector;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.converter.Converter;
import fr.xephi.authme.datasource.converter.CrazyLoginConverter;
@@ -16,6 +15,7 @@ import fr.xephi.authme.datasource.converter.vAuthConverter;
import fr.xephi.authme.datasource.converter.xAuthConverter;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -31,7 +31,7 @@ public class ConverterCommand implements ExecutableCommand {
static final Map> CONVERTERS = getConverters();
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private BukkitService bukkitService;
@@ -61,7 +61,7 @@ public class ConverterCommand implements ExecutableCommand {
try {
converter.execute(sender);
} catch (Exception e) {
- commandService.send(sender, MessageKey.ERROR);
+ commonService.send(sender, MessageKey.ERROR);
ConsoleLogger.logException("Error during conversion:", e);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java
index 57ff497ab..efe9251ea 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/GetEmailCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
+import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -19,7 +19,7 @@ public class GetEmailCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(CommandSender sender, List arguments) {
@@ -27,7 +27,7 @@ public class GetEmailCommand implements ExecutableCommand {
PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
} else {
sender.sendMessage("[AuthMe] " + playerName + "'s email: " + auth.getEmail());
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java
index 3c2b8cd5d..a7b622d3b 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/LastLoginCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
+import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -20,16 +20,16 @@ public class LastLoginCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(CommandSender sender, List arguments) {
// Get the player
- String playerName = (arguments.size() >= 1) ? arguments.get(0) : sender.getName();
+ String playerName = arguments.isEmpty() ? sender.getName() : arguments.get(0);
PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) {
- commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
+ commonService.send(sender, MessageKey.USER_NOT_REGISTERED);
return;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java
index fa45367f9..3a32c8ee2 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/PurgeLastPositionCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
+import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -19,7 +19,7 @@ public class PurgeLastPositionCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(final CommandSender sender, List arguments) {
@@ -35,7 +35,7 @@ public class PurgeLastPositionCommand implements ExecutableCommand {
// Get the user auth and make sure the user exists
PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
index 784e9f4fc..cba5edf0d 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java
@@ -3,13 +3,13 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.limbo.LimboCache;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender;
@@ -27,7 +27,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
private PasswordSecurity passwordSecurity;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private DataSource dataSource;
@@ -51,7 +51,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
// Command logic
ValidationResult passwordValidation = validationService.validatePassword(playerPass, playerName);
if (passwordValidation.hasError()) {
- commandService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs());
+ commonService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return;
}
@@ -60,7 +60,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Override
public void run() {
if (dataSource.isAuthAvailable(playerNameLowerCase)) {
- commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
+ commonService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
return;
}
HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase);
@@ -71,12 +71,12 @@ public class RegisterAdminCommand implements ExecutableCommand {
.build();
if (!dataSource.saveAuth(auth)) {
- commandService.send(sender, MessageKey.ERROR);
+ commonService.send(sender, MessageKey.ERROR);
return;
}
dataSource.setUnlogged(playerNameLowerCase);
- commandService.send(sender, MessageKey.REGISTER_SUCCESS);
+ commonService.send(sender, MessageKey.REGISTER_SUCCESS);
ConsoleLogger.info(sender.getName() + " registered " + playerName);
final Player player = bukkitService.getPlayerExact(playerName);
if (player != null) {
@@ -84,7 +84,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Override
public void run() {
limboCache.restoreData(player);
- player.kickPlayer(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER));
+ player.kickPlayer(commonService.retrieveSingleMessage(MessageKey.KICK_FOR_ADMIN_REGISTER));
}
});
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
index dc1ba6389..037846aaf 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
@@ -3,12 +3,12 @@ package fr.xephi.authme.command.executable.authme;
import ch.jalu.injector.Injector;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender;
@@ -35,7 +35,7 @@ public class ReloadCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void executeCommand(CommandSender sender, List arguments) {
@@ -48,7 +48,7 @@ public class ReloadCommand implements ExecutableCommand {
sender.sendMessage("Note: cannot change database type during /authme reload");
}
performReloadOnServices();
- commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
+ commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
ConsoleLogger.logException("Aborting! Encountered exception during reload of AuthMe:", e);
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java
index 18eb29f56..987338fa2 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java
@@ -1,12 +1,13 @@
package fr.xephi.authme.command.executable.authme;
+import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.command.CommandService;
-import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
+import fr.xephi.authme.service.ValidationService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -21,7 +22,7 @@ public class SetEmailCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private PlayerCache playerCache;
@@ -29,6 +30,9 @@ public class SetEmailCommand implements ExecutableCommand {
@Inject
private BukkitService bukkitService;
+ @Inject
+ private ValidationService validationService;
+
@Override
public void executeCommand(final CommandSender sender, List arguments) {
// Get the player name and email address
@@ -36,8 +40,8 @@ public class SetEmailCommand implements ExecutableCommand {
final String playerEmail = arguments.get(1);
// Validate the email address
- if (!commandService.validateEmail(playerEmail)) {
- commandService.send(sender, MessageKey.INVALID_EMAIL);
+ if (!validationService.validateEmail(playerEmail)) {
+ commonService.send(sender, MessageKey.INVALID_EMAIL);
return;
}
@@ -47,17 +51,17 @@ public class SetEmailCommand implements ExecutableCommand {
// Validate the user
PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
return;
- } else if (!commandService.isEmailFreeForRegistration(playerEmail, sender)) {
- commandService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR);
+ } else if (!validationService.isEmailFreeForRegistration(playerEmail, sender)) {
+ commonService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR);
return;
}
// Set the email address
auth.setEmail(playerEmail);
if (!dataSource.updateEmail(auth)) {
- commandService.send(sender, MessageKey.ERROR);
+ commonService.send(sender, MessageKey.ERROR);
return;
}
@@ -67,7 +71,7 @@ public class SetEmailCommand implements ExecutableCommand {
}
// Show a status message
- commandService.send(sender, MessageKey.EMAIL_CHANGED_SUCCESS);
+ commonService.send(sender, MessageKey.EMAIL_CHANGED_SUCCESS);
}
});
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
index 345351d99..d8901994e 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
@@ -1,11 +1,11 @@
package fr.xephi.authme.command.executable.authme;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -21,7 +21,7 @@ public class UnregisterAdminCommand implements ExecutableCommand {
private DataSource dataSource;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private BukkitService bukkitService;
@@ -38,7 +38,7 @@ public class UnregisterAdminCommand implements ExecutableCommand {
// Make sure the user exists
if (!dataSource.isAuthAvailable(playerName)) {
- commandService.send(sender, MessageKey.UNKNOWN_USER);
+ commonService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java
index 44917f056..f39c7abb4 100644
--- a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java
@@ -1,11 +1,13 @@
package fr.xephi.authme.command.executable.captcha;
+import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.CaptchaManager;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -20,7 +22,7 @@ public class CaptchaCommand extends PlayerCommand {
private CaptchaManager captchaManager;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private LimboCache limboCache;
@@ -30,9 +32,9 @@ public class CaptchaCommand extends PlayerCommand {
final String playerName = player.getName().toLowerCase();
if (playerCache.isAuthenticated(playerName)) {
- commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
+ commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
} else if (!captchaManager.isCaptchaRequired(playerName)) {
- commandService.send(player, MessageKey.USAGE_LOGIN);
+ commonService.send(player, MessageKey.USAGE_LOGIN);
} else {
checkCaptcha(player, arguments.get(0));
}
@@ -46,7 +48,7 @@ public class CaptchaCommand extends PlayerCommand {
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(false);
} else {
String newCode = captchaManager.generateCode(player.getName());
- commandService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
+ commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
index bfcdbe778..4403c982c 100644
--- a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.changepassword;
-import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
+import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.entity.Player;
@@ -18,7 +18,7 @@ import java.util.List;
public class ChangePasswordCommand extends PlayerCommand {
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private PlayerCache playerCache;
@@ -36,14 +36,14 @@ public class ChangePasswordCommand extends PlayerCommand {
String name = player.getName().toLowerCase();
if (!playerCache.isAuthenticated(name)) {
- commandService.send(player, MessageKey.NOT_LOGGED_IN);
+ commonService.send(player, MessageKey.NOT_LOGGED_IN);
return;
}
// Make sure the password is allowed
ValidationResult passwordValidation = validationService.validatePassword(newPassword, name);
if (passwordValidation.hasError()) {
- commandService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
+ commonService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return;
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java
index 85baa2d65..eae64fdb0 100644
--- a/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/email/AddEmailCommand.java
@@ -1,9 +1,9 @@
package fr.xephi.authme.command.executable.email;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -18,7 +18,7 @@ public class AddEmailCommand extends PlayerCommand {
private Management management;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Override
public void runCommand(Player player, List arguments) {
@@ -29,7 +29,7 @@ public class AddEmailCommand extends PlayerCommand {
// Closer inspection of the mail address handled by the async task
management.performAddEmail(player, email);
} else {
- commandService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE);
+ commonService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE);
}
}
}
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 89138b413..c3acb475b 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
@@ -1,17 +1,17 @@
package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.command.CommandService;
-import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
-import fr.xephi.authme.util.RandomStringUtils;
import fr.xephi.authme.security.crypts.HashedPassword;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.RecoveryCodeService;
+import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -28,7 +28,7 @@ public class RecoverEmailCommand extends PlayerCommand {
private PasswordSecurity passwordSecurity;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private DataSource dataSource;
@@ -49,23 +49,23 @@ public class RecoverEmailCommand extends PlayerCommand {
if (!sendMailSsl.hasAllInformation()) {
ConsoleLogger.warning("Mail API is not set");
- commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
+ commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
return;
}
if (playerCache.isAuthenticated(playerName)) {
- commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
+ commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return;
}
PlayerAuth auth = dataSource.getAuth(playerName); // TODO: Create method to get email only
if (auth == null) {
- commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
+ commonService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
return;
}
final String email = auth.getEmail();
if (email == null || !email.equalsIgnoreCase(playerMail) || "your@email.com".equalsIgnoreCase(email)) {
- commandService.send(player, MessageKey.INVALID_EMAIL);
+ commonService.send(player, MessageKey.INVALID_EMAIL);
return;
}
@@ -84,28 +84,35 @@ public class RecoverEmailCommand extends PlayerCommand {
private void createAndSendRecoveryCode(Player player, String email) {
String recoveryCode = recoveryCodeService.generateCode(player.getName());
- sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode);
- commandService.send(player, MessageKey.RECOVERY_CODE_SENT);
+ boolean couldSendMail = sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode);
+ if (couldSendMail) {
+ commonService.send(player, MessageKey.RECOVERY_CODE_SENT);
+ } else {
+ commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
+ }
}
private void processRecoveryCode(Player player, String code, String email) {
final String name = player.getName();
- if (!recoveryCodeService.isCodeValid(name, code)) {
- commandService.send(player, MessageKey.INCORRECT_RECOVERY_CODE);
- return;
+ if (recoveryCodeService.isCodeValid(name, code)) {
+ generateAndSendNewPassword(player, email);
+ recoveryCodeService.removeCode(name);
+ } else {
+ commonService.send(player, MessageKey.INCORRECT_RECOVERY_CODE);
}
-
- generateAndSendNewPassword(player, email);
- recoveryCodeService.removeCode(name);
}
private void generateAndSendNewPassword(Player player, String email) {
String name = player.getName();
- String thePass = RandomStringUtils.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH));
+ String thePass = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
HashedPassword hashNew = passwordSecurity.computeHash(thePass, name);
dataSource.updatePassword(name, hashNew);
- sendMailSsl.sendPasswordMail(name, email, thePass);
- commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
+ boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, thePass);
+ if (couldSendMail) {
+ commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
+ } else {
+ commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
+ }
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java
index ae55c628a..151236e1a 100644
--- a/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/email/ShowEmailCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.email;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -14,8 +14,9 @@ import java.util.List;
* Show email command.
*/
public class ShowEmailCommand extends PlayerCommand {
+
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private PlayerCache playerCache;
@@ -23,10 +24,10 @@ public class ShowEmailCommand extends PlayerCommand {
@Override
public void runCommand(Player player, List arguments) {
PlayerAuth auth = playerCache.getAuth(player.getName());
- if (auth.getEmail() != null && !auth.getEmail().equalsIgnoreCase("your@email.com")) {
- commandService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail());
+ if (auth.getEmail() != null && !"your@email.com".equalsIgnoreCase(auth.getEmail())) {
+ commonService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail());
} else {
- commandService.send(player, MessageKey.SHOW_NO_EMAIL);
+ commonService.send(player, MessageKey.SHOW_NO_EMAIL);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
index f49ec2db2..cc18adbf0 100644
--- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java
@@ -1,15 +1,16 @@
package fr.xephi.authme.command.executable.register;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm;
-import fr.xephi.authme.util.RandomStringUtils;
+import fr.xephi.authme.service.CommonService;
+import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
+import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -20,20 +21,26 @@ import static fr.xephi.authme.settings.properties.RegistrationSettings.ENABLE_CO
import static fr.xephi.authme.settings.properties.RegistrationSettings.USE_EMAIL_REGISTRATION;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION;
+/**
+ * Command for /register.
+ */
public class RegisterCommand extends PlayerCommand {
@Inject
private Management management;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private SendMailSSL sendMailSsl;
+ @Inject
+ private ValidationService validationService;
+
@Override
public void runCommand(Player player, List arguments) {
- if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
+ if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
//for two factor auth we don't need to check the usage
management.performRegister(player, "", "", true);
return;
@@ -42,11 +49,11 @@ public class RegisterCommand extends PlayerCommand {
// Ensure that there is 1 argument, or 2 if confirmation is required
final boolean useConfirmation = isConfirmationRequired();
if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) {
- commandService.send(player, MessageKey.USAGE_REGISTER);
+ commonService.send(player, MessageKey.USAGE_REGISTER);
return;
}
- if (commandService.getProperty(USE_EMAIL_REGISTRATION)) {
+ if (commonService.getProperty(USE_EMAIL_REGISTRATION)) {
handleEmailRegistration(player, arguments);
} else {
handlePasswordRegistration(player, arguments);
@@ -59,8 +66,8 @@ public class RegisterCommand extends PlayerCommand {
}
private void handlePasswordRegistration(Player player, List arguments) {
- if (commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) {
- commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
+ if (commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) {
+ commonService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
} else {
management.performRegister(player, arguments.get(0), "", true);
}
@@ -68,19 +75,19 @@ public class RegisterCommand extends PlayerCommand {
private void handleEmailRegistration(Player player, List arguments) {
if (!sendMailSsl.hasAllInformation()) {
- commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
+ commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
return;
}
final String email = arguments.get(0);
- if (!commandService.validateEmail(email)) {
- commandService.send(player, MessageKey.INVALID_EMAIL);
- } else if (commandService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) {
- commandService.send(player, MessageKey.USAGE_REGISTER);
+ if (!validationService.validateEmail(email)) {
+ commonService.send(player, MessageKey.INVALID_EMAIL);
+ } else if (commonService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) {
+ commonService.send(player, MessageKey.USAGE_REGISTER);
} else {
- String thePass = RandomStringUtils.generate(commandService.getProperty(RECOVERY_PASSWORD_LENGTH));
+ String thePass = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
management.performRegister(player, thePass, email, true);
}
}
@@ -91,8 +98,8 @@ public class RegisterCommand extends PlayerCommand {
* @return True if the confirmation is needed, false otherwise
*/
private boolean isConfirmationRequired() {
- return commandService.getProperty(USE_EMAIL_REGISTRATION)
- ? commandService.getProperty(ENABLE_CONFIRM_EMAIL)
- : commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION);
+ return commonService.getProperty(USE_EMAIL_REGISTRATION)
+ ? commonService.getProperty(ENABLE_CONFIRM_EMAIL)
+ : commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
index c3aaf58a7..09b996a27 100644
--- a/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/unregister/UnregisterCommand.java
@@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.unregister;
-import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
+import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
+import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -19,7 +19,7 @@ public class UnregisterCommand extends PlayerCommand {
private Management management;
@Inject
- private CommandService commandService;
+ private CommonService commonService;
@Inject
private PlayerCache playerCache;
@@ -31,7 +31,7 @@ public class UnregisterCommand extends PlayerCommand {
// Make sure the player is authenticated
if (!playerCache.isAuthenticated(playerName)) {
- commandService.send(player, MessageKey.NOT_LOGGED_IN);
+ commonService.send(player, MessageKey.NOT_LOGGED_IN);
return;
}
diff --git a/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java b/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java
index e4fd9230f..f6ef65a7a 100644
--- a/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java
+++ b/src/main/java/fr/xephi/authme/data/auth/PlayerAuth.java
@@ -189,7 +189,7 @@ public class PlayerAuth {
* @return String
*/
public String serialize() {
- StringBuffer str = new StringBuffer();
+ StringBuilder str = new StringBuilder();
char d = ';';
str.append(this.nickname).append(d);
str.append(this.realName).append(d);
diff --git a/src/main/java/fr/xephi/authme/data/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/data/limbo/LimboCache.java
index 82e42fba8..893aba229 100644
--- a/src/main/java/fr/xephi/authme/data/limbo/LimboCache.java
+++ b/src/main/java/fr/xephi/authme/data/limbo/LimboCache.java
@@ -84,10 +84,10 @@ public class LimboCache {
float walkSpeed = data.getWalkSpeed();
float flySpeed = data.getFlySpeed();
// Reset the speed value if it was 0
- if(walkSpeed == 0f) {
+ if(walkSpeed < 0.01f) {
walkSpeed = 0.2f;
}
- if(flySpeed == 0f) {
+ if(flySpeed < 0.01f) {
flySpeed = 0.2f;
}
player.setWalkSpeed(walkSpeed);
diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
index ebd9299ef..fbbaa5076 100644
--- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
@@ -1,6 +1,5 @@
package fr.xephi.authme.datasource;
-import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@@ -11,15 +10,13 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -48,17 +45,12 @@ public class CacheDataSource implements DataSource {
.build(new CacheLoader>() {
@Override
public Optional load(String key) {
- return Optional.fromNullable(source.getAuth(key));
+ return Optional.ofNullable(source.getAuth(key));
}
@Override
public ListenableFuture> reload(final String key, Optional oldValue) {
- return executorService.submit(new Callable>() {
- @Override
- public Optional call() {
- return load(key);
- }
- });
+ return executorService.submit(() -> load(key));
}
});
}
@@ -90,7 +82,7 @@ public class CacheDataSource implements DataSource {
@Override
public PlayerAuth getAuth(String user) {
user = user.toLowerCase();
- return cachedAuths.getUnchecked(user).orNull();
+ return cachedAuths.getUnchecked(user).orElse(null);
}
@Override
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index 49b5442d1..8c1ecf4b5 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -9,7 +9,6 @@ import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@@ -295,19 +294,11 @@ public class FlatFile implements DataSource {
break;
}
}
- } catch (FileNotFoundException ex) {
- ConsoleLogger.warning(ex.getMessage());
- return false;
} catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage());
return false;
} finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
+ silentClose(br);
}
if (newAuth != null) {
removeAuth(auth.getNickname());
@@ -330,19 +321,11 @@ public class FlatFile implements DataSource {
}
}
return countIp;
- } catch (FileNotFoundException ex) {
- ConsoleLogger.warning(ex.getMessage());
- return new ArrayList<>();
} catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage());
return new ArrayList<>();
} finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
+ silentClose(br);
}
}
@@ -363,12 +346,7 @@ public class FlatFile implements DataSource {
} catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage());
} finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
+ silentClose(br);
}
return 0;
}
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 9da225b94..20ffa6d53 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -5,9 +5,6 @@ import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.datasource.Columns;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.XFBCRYPT;
@@ -15,8 +12,8 @@ import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.util.RuntimeUtils;
import fr.xephi.authme.util.StringUtils;
+import fr.xephi.authme.util.Utils;
import java.sql.Blob;
import java.sql.Connection;
@@ -50,7 +47,7 @@ public class MySQL implements DataSource {
private int phpBbGroup;
private String wordpressPrefix;
- public MySQL(Settings settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
+ public MySQL(Settings settings) throws ClassNotFoundException, SQLException {
setParameters(settings);
// Set the connection arguments (and check if connection is ok)
@@ -100,17 +97,17 @@ public class MySQL implements DataSource {
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
- if(poolSize == -1) {
- poolSize = RuntimeUtils.getCoreCount();
+ if (poolSize == -1) {
+ poolSize = Utils.getCoreCount();
}
}
- private void setConnectionArguments() throws RuntimeException {
+ private void setConnectionArguments() {
ds = new HikariDataSource();
ds.setPoolName("AuthMeMYSQLPool");
// Pool size
- ds.setMaximumPoolSize(poolSize);
+ ds.setMaximumPoolSize(poolSize);
// Database URL
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);
@@ -137,7 +134,7 @@ public class MySQL implements DataSource {
}
@Override
- public void reload() throws RuntimeException {
+ public void reload() {
if (ds != null) {
ds.close();
}
diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java
index d19c4aa22..fdb9c9197 100644
--- a/src/main/java/fr/xephi/authme/datasource/SQLite.java
+++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java
@@ -3,9 +3,6 @@ package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.datasource.Columns;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
@@ -397,7 +394,7 @@ public class SQLite implements DataSource {
}
}
- private void close(Statement st) {
+ private static void close(Statement st) {
if (st != null) {
try {
st.close();
@@ -407,7 +404,7 @@ public class SQLite implements DataSource {
}
}
- private void close(Connection con) {
+ private static void close(Connection con) {
if (con != null) {
try {
con.close();
@@ -417,7 +414,7 @@ public class SQLite implements DataSource {
}
}
- private void close(ResultSet rs) {
+ private static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
@@ -479,7 +476,7 @@ public class SQLite implements DataSource {
pst.setString(1, user);
rs = pst.executeQuery();
if (rs.next())
- return (rs.getInt(col.IS_LOGGED) == 1);
+ return rs.getInt(col.IS_LOGGED) == 1;
} catch (SQLException ex) {
logSqlException(ex);
} finally {
diff --git a/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java
index 535c0ebab..13266a891 100644
--- a/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java
+++ b/src/main/java/fr/xephi/authme/datasource/converter/CrazyLoginConverter.java
@@ -43,20 +43,7 @@ public class CrazyLoginConverter implements Converter {
try (BufferedReader users = new BufferedReader(new FileReader(source))) {
while ((line = users.readLine()) != null) {
if (line.contains("|")) {
- String[] args = line.split("\\|");
- if (args.length < 2 || "name".equalsIgnoreCase(args[0])) {
- continue;
- }
- String playerName = args[0];
- String password = args[1];
- if (password != null) {
- PlayerAuth auth = PlayerAuth.builder()
- .name(playerName.toLowerCase())
- .realName(playerName)
- .password(password, null)
- .build();
- database.saveAuth(auth);
- }
+ migrateAccount(line);
}
}
ConsoleLogger.info("CrazyLogin database has been imported correctly");
@@ -66,4 +53,26 @@ public class CrazyLoginConverter implements Converter {
}
}
+ /**
+ * Moves an account from CrazyLogin to the AuthMe database.
+ *
+ * @param line line read from the CrazyLogin file (one account)
+ */
+ private void migrateAccount(String line) {
+ String[] args = line.split("\\|");
+ if (args.length < 2 || "name".equalsIgnoreCase(args[0])) {
+ return;
+ }
+ String playerName = args[0];
+ String password = args[1];
+ if (password != null) {
+ PlayerAuth auth = PlayerAuth.builder()
+ .name(playerName.toLowerCase())
+ .realName(playerName)
+ .password(password, null)
+ .build();
+ database.saveAuth(auth);
+ }
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java b/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java
new file mode 100644
index 000000000..686059539
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/DataSourceProvider.java
@@ -0,0 +1,123 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.datasource.CacheDataSource;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.datasource.DataSourceType;
+import fr.xephi.authme.datasource.FlatFile;
+import fr.xephi.authme.datasource.MySQL;
+import fr.xephi.authme.datasource.SQLite;
+import fr.xephi.authme.datasource.converter.ForceFlatToSqlite;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+
+/**
+ * Creates the AuthMe data source.
+ */
+public class DataSourceProvider implements Provider {
+
+ private static final String FLATFILE_FILENAME = "auths.db";
+ private static final int SQLITE_MAX_SIZE = 4000;
+
+ @Inject
+ @DataFolder
+ private File dataFolder;
+ @Inject
+ private Settings settings;
+ @Inject
+ private BukkitService bukkitService;
+
+ DataSourceProvider() {
+ }
+
+ @Override
+ public DataSource get() {
+ try {
+ return createDataSource();
+ } catch (Exception e) {
+ ConsoleLogger.logException("Could not create data source:", e);
+ throw new IllegalStateException("Error during initialization of data source", e);
+ }
+ }
+
+ /**
+ * Sets up the data source.
+ *
+ * @return the constructed datasource
+ * @throws ClassNotFoundException if no driver could be found for the datasource
+ * @throws SQLException when initialization of a SQL datasource failed
+ * @throws IOException if flat file cannot be read
+ */
+ private DataSource createDataSource() throws ClassNotFoundException, SQLException, IOException {
+ DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
+ DataSource dataSource;
+ switch (dataSourceType) {
+ case FILE:
+ File source = new File(dataFolder, FLATFILE_FILENAME);
+ dataSource = new FlatFile(source);
+ break;
+ case MYSQL:
+ dataSource = new MySQL(settings);
+ break;
+ case SQLITE:
+ dataSource = new SQLite(settings);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
+ }
+
+ dataSource = convertFlatfileToSqlite(dataSource);
+
+ if (settings.getProperty(DatabaseSettings.USE_CACHING)) {
+ dataSource = new CacheDataSource(dataSource);
+ }
+ if (DataSourceType.SQLITE.equals(dataSourceType)) {
+ checkDataSourceSize(dataSource, bukkitService);
+ }
+ return dataSource;
+ }
+
+ private void checkDataSourceSize(final DataSource dataSource, BukkitService bukkitService) {
+ bukkitService.runTaskAsynchronously(() -> {
+ int accounts = dataSource.getAccountsRegistered();
+ if (accounts >= SQLITE_MAX_SIZE) {
+ ConsoleLogger.warning("YOU'RE USING THE SQLITE DATABASE WITH "
+ + accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
+ }
+ });
+ }
+
+ /**
+ * Converts the data source from the deprecated FLATFILE type to SQLITE.
+ *
+ * @param dataSource the data source to convert if necessary
+ * @return the data source to use: the converted datasource (SQLite),
+ * or the same data source if no conversion was performed
+ */
+ private DataSource convertFlatfileToSqlite(DataSource dataSource) {
+ if (DataSourceType.FILE == settings.getProperty(DatabaseSettings.BACKEND)) {
+ ConsoleLogger.warning("FlatFile backend has been detected and is now deprecated; it will be changed "
+ + "to SQLite... Connection will be impossible until conversion is done!");
+ FlatFile flatFile = (FlatFile) dataSource;
+ try {
+ SQLite sqlite = new SQLite(settings);
+ ForceFlatToSqlite converter = new ForceFlatToSqlite(flatFile, sqlite);
+ converter.execute(null);
+ settings.setProperty(DatabaseSettings.BACKEND, DataSourceType.SQLITE);
+ settings.save();
+ return sqlite;
+ } catch (Exception e) {
+ ConsoleLogger.logException("Error during conversion from Flatfile to SQLite", e);
+ throw new IllegalStateException(e);
+ }
+ }
+ return dataSource;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/HasCleanup.java b/src/main/java/fr/xephi/authme/initialization/HasCleanup.java
index db047d840..351df4f69 100644
--- a/src/main/java/fr/xephi/authme/initialization/HasCleanup.java
+++ b/src/main/java/fr/xephi/authme/initialization/HasCleanup.java
@@ -3,6 +3,8 @@ package fr.xephi.authme.initialization;
/**
* Common interface for types which have data that becomes outdated
* and that can be cleaned up periodically.
+ *
+ * @see fr.xephi.authme.task.CleanupTask
*/
public interface HasCleanup {
diff --git a/src/main/java/fr/xephi/authme/initialization/Initializer.java b/src/main/java/fr/xephi/authme/initialization/Initializer.java
deleted file mode 100644
index 525334c27..000000000
--- a/src/main/java/fr/xephi/authme/initialization/Initializer.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import com.github.authme.configme.knownproperties.ConfigurationData;
-import com.github.authme.configme.resource.PropertyResource;
-import com.github.authme.configme.resource.YamlFileResource;
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.data.auth.PlayerAuth;
-import fr.xephi.authme.datasource.CacheDataSource;
-import fr.xephi.authme.datasource.DataSource;
-import fr.xephi.authme.datasource.DataSourceType;
-import fr.xephi.authme.datasource.FlatFile;
-import fr.xephi.authme.datasource.MySQL;
-import fr.xephi.authme.datasource.SQLite;
-import fr.xephi.authme.message.MessageKey;
-import fr.xephi.authme.message.Messages;
-import fr.xephi.authme.output.ConsoleFilter;
-import fr.xephi.authme.output.Log4JFilter;
-import fr.xephi.authme.service.BukkitService;
-import fr.xephi.authme.service.MigrationService;
-import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.settings.SettingsMigrationService;
-import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
-import fr.xephi.authme.settings.properties.DatabaseSettings;
-import fr.xephi.authme.settings.properties.EmailSettings;
-import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.util.FileUtils;
-import fr.xephi.authme.util.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-
-import java.io.File;
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.logging.Logger;
-
-import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE;
-import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
-
-/**
- * Initializes various services.
- */
-public class Initializer {
-
- private static final String FLATFILE_FILENAME = "auths.db";
- private static final int SQLITE_MAX_SIZE = 4000;
-
- private AuthMe authMe;
- private BukkitService bukkitService;
-
- public Initializer(AuthMe authMe, BukkitService bukkitService) {
- this.authMe = authMe;
- this.bukkitService = bukkitService;
- }
-
- /**
- * Loads the plugin's settings.
- *
- * @param authMe the plugin instance
- * @return the settings instance, or null if it could not be constructed
- */
- public static Settings createSettings(AuthMe authMe) throws Exception {
- File configFile = new File(authMe.getDataFolder(), "config.yml");
- if(!configFile.exists()) {
- configFile.createNewFile();
- }
- PropertyResource resource = new YamlFileResource(configFile);
- SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder());
- ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
- return new Settings(authMe.getDataFolder(), resource, migrationService, configurationData);
- }
-
- /**
- * Sets up the data source.
- *
- * @param settings the settings
- * @return the constructed datasource
- * @throws ClassNotFoundException if no driver could be found for the datasource
- * @throws SQLException when initialization of a SQL datasource failed
- * @throws IOException if flat file cannot be read
- */
- public DataSource setupDatabase(Settings settings) throws ClassNotFoundException, SQLException, IOException {
- DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
- DataSource dataSource;
- switch (dataSourceType) {
- case FILE:
- File source = new File(authMe.getDataFolder(), FLATFILE_FILENAME);
- dataSource = new FlatFile(source);
- break;
- case MYSQL:
- dataSource = new MySQL(settings);
- break;
- case SQLITE:
- dataSource = new SQLite(settings);
- break;
- default:
- throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
- }
-
- DataSource convertedSource = MigrationService.convertFlatfileToSqlite(settings, dataSource);
- dataSource = convertedSource == null ? dataSource : convertedSource;
-
- if (settings.getProperty(DatabaseSettings.USE_CACHING)) {
- dataSource = new CacheDataSource(dataSource);
- }
- if (DataSourceType.SQLITE.equals(dataSourceType)) {
- checkDataSourceSize(dataSource);
- }
- return dataSource;
- }
-
- private void checkDataSourceSize(final DataSource dataSource) {
- bukkitService.runTaskAsynchronously(new Runnable() {
- @Override
- public void run() {
- int accounts = dataSource.getAccountsRegistered();
- if (accounts >= SQLITE_MAX_SIZE) {
- ConsoleLogger.warning("YOU'RE USING THE SQLITE DATABASE WITH "
- + accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
- }
- }
- });
- }
-
- /**
- * Sets up the console filter if enabled.
- *
- * @param settings the settings
- * @param logger the plugin logger
- */
- public void setupConsoleFilter(Settings settings, Logger logger) {
- if (!settings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
- return;
- }
- // Try to set the log4j filter
- try {
- Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter");
- setLog4JFilter();
- } catch (ClassNotFoundException | NoClassDefFoundError e) {
- // log4j is not available
- ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled");
- ConsoleFilter filter = new ConsoleFilter();
- logger.setFilter(filter);
- Bukkit.getLogger().setFilter(filter);
- Logger.getLogger("Minecraft").setFilter(filter);
- }
- }
-
- // Set the console filter to remove the passwords
- private static void setLog4JFilter() {
- org.apache.logging.log4j.core.Logger logger;
- logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
- logger.addFilter(new Log4JFilter());
- }
-
- public void scheduleRecallEmailTask(Settings settings, final DataSource dataSource, final Messages messages) {
- if (!settings.getProperty(RECALL_PLAYERS)) {
- return;
- }
- bukkitService.runTaskTimerAsynchronously(new Runnable() {
- @Override
- public void run() {
- for (PlayerAuth auth : dataSource.getLoggedPlayers()) {
- String email = auth.getEmail();
- if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
- Player player = bukkitService.getPlayerExact(auth.getRealName());
- if (player != null) {
- messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
- }
- }
- }
- }
- }, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
- }
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/MetricsManager.java b/src/main/java/fr/xephi/authme/initialization/MetricsManager.java
deleted file mode 100644
index e22e742e4..000000000
--- a/src/main/java/fr/xephi/authme/initialization/MetricsManager.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package fr.xephi.authme.initialization;
-
-import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.settings.properties.DatabaseSettings;
-import fr.xephi.authme.settings.properties.PluginSettings;
-import org.mcstats.Metrics;
-import org.mcstats.Metrics.Graph;
-
-import java.io.IOException;
-
-public class MetricsManager {
-
- private MetricsManager() {
- }
-
- public static void sendMetrics(AuthMe plugin, Settings settings) {
- try {
- final Metrics metrics = new Metrics(plugin);
-
- final Graph languageGraph = metrics.createGraph("Messages Language");
- final String messagesLanguage = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
- languageGraph.addPlotter(new Metrics.Plotter(messagesLanguage) {
- @Override
- public int getValue() {
- return 1;
- }
- });
-
- final Graph databaseBackend = metrics.createGraph("Database Backend");
- final String dataSource = settings.getProperty(DatabaseSettings.BACKEND).toString();
- databaseBackend.addPlotter(new Metrics.Plotter(dataSource) {
- @Override
- public int getValue() {
- return 1;
- }
- });
-
- // Submit metrics
- metrics.start();
- } catch (IOException e) {
- // Failed to submit the metrics data
- ConsoleLogger.logException("Can't send Metrics data! The plugin will work anyway...", e);
- }
- }
-}
diff --git a/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java b/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java
index 6141e47ef..1e7862443 100644
--- a/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java
+++ b/src/main/java/fr/xephi/authme/initialization/OnShutdownPlayerSaver.java
@@ -76,10 +76,8 @@ public class OnShutdownPlayerSaver {
dataSource.updateQuitLoc(auth);
}
if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
- && !settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
- if (!limboPlayerStorage.hasData(player)) {
- limboPlayerStorage.saveData(player);
- }
+ && !settings.getProperty(RestrictionSettings.NO_TELEPORT) && !limboPlayerStorage.hasData(player)) {
+ limboPlayerStorage.saveData(player);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java b/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java
new file mode 100644
index 000000000..0dd421817
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java
@@ -0,0 +1,127 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.data.auth.PlayerAuth;
+import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.message.Messages;
+import fr.xephi.authme.output.ConsoleFilter;
+import fr.xephi.authme.output.Log4JFilter;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+import fr.xephi.authme.settings.properties.EmailSettings;
+import fr.xephi.authme.settings.properties.PluginSettings;
+import fr.xephi.authme.settings.properties.SecuritySettings;
+import fr.xephi.authme.util.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.mcstats.Metrics;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE;
+import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
+
+/**
+ * Contains actions such as migrations that should be performed on startup.
+ */
+public class OnStartupTasks {
+
+ @Inject
+ private DataSource dataSource;
+ @Inject
+ private Settings settings;
+ @Inject
+ private BukkitService bukkitService;
+ @Inject
+ private Messages messages;
+
+ OnStartupTasks() {
+ }
+
+ public static void sendMetrics(AuthMe plugin, Settings settings) {
+ try {
+ final Metrics metrics = new Metrics(plugin);
+
+ final Metrics.Graph languageGraph = metrics.createGraph("Messages Language");
+ final String messagesLanguage = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
+ languageGraph.addPlotter(new Metrics.Plotter(messagesLanguage) {
+ @Override
+ public int getValue() {
+ return 1;
+ }
+ });
+
+ final Metrics.Graph databaseBackend = metrics.createGraph("Database Backend");
+ final String dataSource = settings.getProperty(DatabaseSettings.BACKEND).toString();
+ databaseBackend.addPlotter(new Metrics.Plotter(dataSource) {
+ @Override
+ public int getValue() {
+ return 1;
+ }
+ });
+
+ // Submit metrics
+ metrics.start();
+ } catch (IOException e) {
+ // Failed to submit the metrics data
+ ConsoleLogger.logException("Can't send Metrics data! The plugin will work anyway...", e);
+ }
+ }
+
+ /**
+ * Sets up the console filter if enabled.
+ *
+ * @param settings the settings
+ * @param logger the plugin logger
+ */
+ public static void setupConsoleFilter(Settings settings, Logger logger) {
+ if (!settings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
+ return;
+ }
+ // Try to set the log4j filter
+ try {
+ Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter");
+ setLog4JFilter();
+ } catch (ClassNotFoundException | NoClassDefFoundError e) {
+ // log4j is not available
+ ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled");
+ ConsoleFilter filter = new ConsoleFilter();
+ logger.setFilter(filter);
+ Bukkit.getLogger().setFilter(filter);
+ Logger.getLogger("Minecraft").setFilter(filter);
+ }
+ }
+
+ // Set the console filter to remove the passwords
+ private static void setLog4JFilter() {
+ org.apache.logging.log4j.core.Logger logger;
+ logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
+ logger.addFilter(new Log4JFilter());
+ }
+
+ public void scheduleRecallEmailTask() {
+ if (!settings.getProperty(RECALL_PLAYERS)) {
+ return;
+ }
+ bukkitService.runTaskTimerAsynchronously(new Runnable() {
+ @Override
+ public void run() {
+ for (PlayerAuth auth : dataSource.getLoggedPlayers()) {
+ String email = auth.getEmail();
+ if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
+ Player player = bukkitService.getPlayerExact(auth.getRealName());
+ if (player != null) {
+ messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
+ }
+ }
+ }
+ }
+ }, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/Reloadable.java b/src/main/java/fr/xephi/authme/initialization/Reloadable.java
index 6b28fc7dd..65c3a3379 100644
--- a/src/main/java/fr/xephi/authme/initialization/Reloadable.java
+++ b/src/main/java/fr/xephi/authme/initialization/Reloadable.java
@@ -2,6 +2,8 @@ package fr.xephi.authme.initialization;
/**
* Interface for reloadable entities.
+ *
+ * @see fr.xephi.authme.command.executable.authme.ReloadCommand
*/
public interface Reloadable {
diff --git a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java b/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
index 487f70d58..89d18318e 100644
--- a/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
+++ b/src/main/java/fr/xephi/authme/initialization/SettingsDependent.java
@@ -4,6 +4,8 @@ import fr.xephi.authme.settings.Settings;
/**
* Interface for classes that keep a local copy of certain settings.
+ *
+ * @see fr.xephi.authme.command.executable.authme.ReloadCommand
*/
public interface SettingsDependent {
diff --git a/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java b/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java
new file mode 100644
index 000000000..f9c8638af
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/SettingsProvider.java
@@ -0,0 +1,45 @@
+package fr.xephi.authme.initialization;
+
+import com.github.authme.configme.knownproperties.ConfigurationData;
+import com.github.authme.configme.resource.PropertyResource;
+import com.github.authme.configme.resource.YamlFileResource;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.SettingsMigrationService;
+import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
+import fr.xephi.authme.util.FileUtils;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import java.io.File;
+
+/**
+ * Initializes the settings.
+ */
+public class SettingsProvider implements Provider {
+
+ @Inject
+ @DataFolder
+ private File dataFolder;
+ @Inject
+ private SettingsMigrationService migrationService;
+
+ SettingsProvider() {
+ }
+
+ /**
+ * Loads the plugin's settings.
+ *
+ * @return the settings instance, or null if it could not be constructed
+ */
+ @Override
+ public Settings get() {
+ File configFile = new File(dataFolder, "config.yml");
+ if (!configFile.exists()) {
+ FileUtils.create(configFile);
+ }
+ PropertyResource resource = new YamlFileResource(configFile);
+ ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
+ return new Settings(dataFolder, resource, migrationService, configurationData);
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
index 93783346d..e3ff4ec5b 100644
--- a/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
+++ b/src/main/java/fr/xephi/authme/listener/OnJoinVerifier.java
@@ -9,14 +9,14 @@ import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.service.AntiBotService;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
-import fr.xephi.authme.service.ValidationService;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerLoginEvent;
@@ -68,10 +68,10 @@ class OnJoinVerifier implements Reloadable {
* @param isAuthAvailable whether or not the player is registered
*/
public void checkAntibot(Player player, boolean isAuthAvailable) throws FailedVerificationException {
- if (permissionsManager.hasPermission(player, PlayerStatePermission.BYPASS_ANTIBOT)) {
+ if (isAuthAvailable || permissionsManager.hasPermission(player, PlayerStatePermission.BYPASS_ANTIBOT)) {
return;
}
- if (antiBotService.shouldKick(isAuthAvailable)) {
+ if (antiBotService.shouldKick()) {
antiBotService.addPlayerKick(player.getName());
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
}
@@ -170,10 +170,9 @@ class OnJoinVerifier implements Reloadable {
public void checkPlayerCountry(boolean isAuthAvailable,
String playerIp) throws FailedVerificationException {
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
- && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
- if (!validationService.isCountryAdmitted(playerIp)) {
+ && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)
+ && !validationService.isCountryAdmitted(playerIp)) {
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
- }
}
}
diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener.java b/src/main/java/fr/xephi/authme/listener/PlayerListener.java
index b6484fb35..c380fbe18 100644
--- a/src/main/java/fr/xephi/authme/listener/PlayerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener.java
@@ -6,14 +6,14 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.AntiBotService;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.TeleportationService;
+import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
-import fr.xephi.authme.service.BukkitService;
-import fr.xephi.authme.service.TeleportationService;
-import fr.xephi.authme.service.ValidationService;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -42,6 +42,7 @@ import org.bukkit.event.player.PlayerShearEntityEvent;
import javax.inject.Inject;
import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -53,7 +54,7 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAU
*/
public class PlayerListener implements Listener {
- public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>();
+ public static final Map joinMessage = new ConcurrentHashMap<>();
@Inject
private Settings settings;
@@ -81,7 +82,7 @@ public class PlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String cmd = event.getMessage().split(" ")[0].toLowerCase();
- if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && cmd.equals("/motd")) {
+ if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) {
return;
}
if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) {
@@ -113,7 +114,7 @@ public class PlayerListener implements Listener {
iter.remove();
}
}
- if (recipients.size() == 0) {
+ if (recipients.isEmpty()) {
event.setCancelled(true);
}
}
@@ -156,9 +157,7 @@ public class PlayerListener implements Listener {
if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn);
- return;
- }
- if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
+ } else if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
player.teleport(spawn);
}
}
@@ -208,9 +207,11 @@ public class PlayerListener implements Listener {
final String name = player.getName();
if (validationService.isUnrestricted(name)) {
return;
- } else if (onJoinVerifier.refusePlayerForFullServer(event)) {
+ }
+ if (onJoinVerifier.refusePlayerForFullServer(event)) {
return;
- } else if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
+ }
+ if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return;
}
@@ -222,9 +223,9 @@ public class PlayerListener implements Listener {
// Get the auth later as this may cause the single session check to fail
// Slow stuff
final PlayerAuth auth = dataSource.getAuth(name);
- final boolean isAuthAvailable = (auth != null);
- onJoinVerifier.checkAntibot(player, isAuthAvailable);
+ final boolean isAuthAvailable = auth != null;
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
+ onJoinVerifier.checkAntibot(player, isAuthAvailable);
onJoinVerifier.checkNameCasing(player, auth);
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress());
} catch (FailedVerificationException e) {
@@ -233,7 +234,6 @@ public class PlayerListener implements Listener {
return;
}
- antiBotService.handlePlayerJoin();
teleportationService.teleportOnJoin(player);
}
@@ -306,27 +306,14 @@ public class PlayerListener implements Listener {
* @note little hack cause InventoryOpenEvent cannot be cancelled for
* real, cause no packet is send to server by client for the main inv
*/
- bukkitService.scheduleSyncDelayedTask(new Runnable() {
- @Override
- public void run() {
- player.closeInventory();
- }
- }, 1);
+ bukkitService.scheduleSyncDelayedTask(player::closeInventory, 1);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInventoryClick(InventoryClickEvent event) {
- if (event.getWhoClicked() == null) {
- return;
+ if (listenerService.shouldCancelEvent(event.getWhoClicked())) {
+ event.setCancelled(true);
}
- if (!(event.getWhoClicked() instanceof Player)) {
- return;
- }
- Player player = (Player) event.getWhoClicked();
- if (!listenerService.shouldCancelEvent(player)) {
- return;
- }
- event.setCancelled(true);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
diff --git a/src/main/java/fr/xephi/authme/listener/PlayerListener111.java b/src/main/java/fr/xephi/authme/listener/PlayerListener111.java
new file mode 100644
index 000000000..43b4ca339
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/listener/PlayerListener111.java
@@ -0,0 +1,24 @@
+package fr.xephi.authme.listener;
+
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityAirChangeEvent;
+
+import javax.inject.Inject;
+
+/**
+ * Listener of player events for events introduced in Minecraft 1.11.
+ */
+public class PlayerListener111 implements Listener {
+
+ @Inject
+ private ListenerService listenerService;
+
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
+ public void onPlayerAirChange(EntityAirChangeEvent event) {
+ if (listenerService.shouldCancelEvent(event)) {
+ event.setCancelled(true);
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
index e629402f1..c90d9422b 100644
--- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
+++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
@@ -1,19 +1,22 @@
package fr.xephi.authme.mail;
-import fr.xephi.authme.AuthMe;
+import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
-import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
+import org.bukkit.Server;
+import javax.activation.CommandMap;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
+import javax.activation.MailcapCommandMap;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.mail.Session;
@@ -27,18 +30,19 @@ import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
/**
- * @author Xephi59
+ * Sends emails to players on behalf of the server.
*/
public class SendMailSSL {
- @Inject
- private AuthMe plugin;
- @Inject
- private Settings settings;
- @Inject
- private BukkitService bukkitService;
+ private final File dataFolder;
+ private final String serverName;
+ private final Settings settings;
- SendMailSSL() {
+ @Inject
+ SendMailSSL(@DataFolder File dataFolder, Server server, Settings settings) {
+ this.dataFolder = dataFolder;
+ this.serverName = server.getServerName();
+ this.settings = settings;
}
/**
@@ -57,62 +61,57 @@ public class SendMailSSL {
* @param name the name of the player
* @param mailAddress the player's email
* @param newPass the new password
+ * @return true if email could be sent, false otherwise
*/
- public void sendPasswordMail(String name, String mailAddress, String newPass) {
+ public boolean sendPasswordMail(String name, String mailAddress, String newPass) {
if (!hasAllInformation()) {
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
- return;
+ return false;
}
- final String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
- bukkitService.runTaskAsynchronously(new Runnable() {
+ HtmlEmail email;
+ try {
+ email = initializeMail(mailAddress);
+ } catch (EmailException e) {
+ ConsoleLogger.logException("Failed to create email with the given settings:", e);
+ return false;
+ }
- @Override
- public void run() {
- HtmlEmail email;
- try {
- email = initializeMail(mailAddress);
- } catch (EmailException e) {
- ConsoleLogger.logException("Failed to create email with the given settings:", e);
- return;
- }
-
- String content = mailText;
- // Generate an image?
- File file = null;
- if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
- try {
- file = generateImage(name, plugin, newPass);
- content = embedImageIntoEmailContent(file, email, content);
- } catch (IOException | EmailException e) {
- ConsoleLogger.logException(
- "Unable to send new password as image for email " + mailAddress + ":", e);
- }
- }
-
- sendEmail(content, email);
- FileUtils.delete(file);
+ String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
+ // Generate an image?
+ File file = null;
+ if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
+ try {
+ file = generateImage(name, newPass);
+ mailText = embedImageIntoEmailContent(file, email, mailText);
+ } catch (IOException | EmailException e) {
+ ConsoleLogger.logException(
+ "Unable to send new password as image for email " + mailAddress + ":", e);
}
- });
+ }
+
+ boolean couldSendEmail = sendEmail(mailText, email);
+ FileUtils.delete(file);
+ return couldSendEmail;
}
- public void sendRecoveryCode(String name, String email, String code) {
- String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
- name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
-
+ public boolean sendRecoveryCode(String name, String email, String code) {
HtmlEmail htmlEmail;
try {
htmlEmail = initializeMail(email);
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email for recovery code:", e);
- return;
+ return false;
}
- sendEmail(message, htmlEmail);
+
+ String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
+ name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
+ return sendEmail(message, htmlEmail);
}
- private static File generateImage(String name, AuthMe plugin, String newPass) throws IOException {
+ private File generateImage(String name, String newPass) throws IOException {
ImageGenerator gen = new ImageGenerator(newPass);
- File file = new File(plugin.getDataFolder(), name + "_new_pass.jpg");
+ File file = new File(dataFolder, name + "_new_pass.jpg");
ImageIO.write(gen.generateImage(), "jpg", file);
return file;
}
@@ -124,7 +123,8 @@ public class SendMailSSL {
return content.replace("", "");
}
- private HtmlEmail initializeMail(String emailAddress) throws EmailException {
+ @VisibleForTesting
+ HtmlEmail initializeMail(String emailAddress) throws EmailException {
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail
@@ -145,8 +145,18 @@ public class SendMailSSL {
return email;
}
- private static boolean sendEmail(String content, HtmlEmail email) {
+ @VisibleForTesting
+ boolean sendEmail(String content, HtmlEmail email) {
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader());
+ // Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative
+ // cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type
+ MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
+ mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
+ mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
+ mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
+ mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
+ mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822");
+
try {
email.setHtmlMsg(content);
email.setTextMsg(content);
@@ -166,14 +176,14 @@ public class SendMailSSL {
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
return mailText
.replace("", name)
- .replace("", plugin.getServer().getServerName())
+ .replace("", serverName)
.replace("", newPass);
}
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
return mailText
.replace("", name)
- .replace("", plugin.getServer().getServerName())
+ .replace("", serverName)
.replace("", code)
.replace("", String.valueOf(hoursValid));
}
diff --git a/src/main/java/fr/xephi/authme/message/MessageFileHandler.java b/src/main/java/fr/xephi/authme/message/MessageFileHandler.java
index e870bdf36..a0d4e947c 100644
--- a/src/main/java/fr/xephi/authme/message/MessageFileHandler.java
+++ b/src/main/java/fr/xephi/authme/message/MessageFileHandler.java
@@ -53,7 +53,7 @@ public class MessageFileHandler {
if (message == null) {
ConsoleLogger.warning("Error getting message with key '" + key + "'. "
- + "Please verify your config file at '" + filename + "'");
+ + "Please update your config file '" + filename + "' (or run /authme messages)");
return getDefault(key);
}
return message;
diff --git a/src/main/java/fr/xephi/authme/message/MessageKey.java b/src/main/java/fr/xephi/authme/message/MessageKey.java
index ed3df4b37..c9fd5fec6 100644
--- a/src/main/java/fr/xephi/authme/message/MessageKey.java
+++ b/src/main/java/fr/xephi/authme/message/MessageKey.java
@@ -5,156 +5,235 @@ package fr.xephi.authme.message;
*/
public enum MessageKey {
+ /** In order to use this command you must be authenticated! */
DENIED_COMMAND("denied_command"),
+ /** A player with the same IP is already in game! */
SAME_IP_ONLINE("same_ip_online"),
+ /** In order to chat you must be authenticated! */
DENIED_CHAT("denied_chat"),
+ /** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */
KICK_ANTIBOT("kick_antibot"),
+ /** Can't find the requested user in the database! */
UNKNOWN_USER("unknown_user"),
+ /** Your quit location was unsafe, you have been teleported to the world's spawnpoint. */
UNSAFE_QUIT_LOCATION("unsafe_spawn"),
+ /** You're not logged in! */
NOT_LOGGED_IN("not_logged_in"),
+ /** You can register yourself to the server with the command "/register >password> >ConfirmPassword>" */
REGISTER_VOLUNTARILY("reg_voluntarily"),
+ /** Usage: /login >password> */
USAGE_LOGIN("usage_log"),
+ /** Wrong password! */
WRONG_PASSWORD("wrong_pwd"),
+ /** Successfully unregistered! */
UNREGISTERED_SUCCESS("unregistered"),
+ /** In-game registration is disabled! */
REGISTRATION_DISABLED("reg_disabled"),
+ /** Logged-in due to Session Reconnection. */
SESSION_RECONNECTION("valid_session"),
+ /** Successful login! */
LOGIN_SUCCESS("login"),
+ /** Your account isn't activated yet, please check your emails! */
ACCOUNT_NOT_ACTIVATED("vb_nonActiv"),
+ /** You already have registered this username! */
NAME_ALREADY_REGISTERED("user_regged"),
+ /** You don't have the permission to perform this action! */
NO_PERMISSION("no_perm"),
+ /** An unexpected error occurred, please contact an administrator! */
ERROR("error"),
+ /** Please, login with the command "/login >password>" */
LOGIN_MESSAGE("login_msg"),
+ /** Please, register to the server with the command "/register >password> >ConfirmPassword>" */
REGISTER_MESSAGE("reg_msg"),
+ /** Please, register to the server with the command "/register >email> >confirmEmail>" */
REGISTER_EMAIL_MESSAGE("reg_email_msg"),
+ /** You have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection! */
MAX_REGISTER_EXCEEDED("max_reg", "%max_acc", "%reg_count", "%reg_names"),
+ /** Usage: /register >password> >ConfirmPassword> */
USAGE_REGISTER("usage_reg"),
+ /** Usage: /unregister >password> */
USAGE_UNREGISTER("usage_unreg"),
+ /** Password changed successfully! */
PASSWORD_CHANGED_SUCCESS("pwd_changed"),
+ /** This user isn't registered! */
USER_NOT_REGISTERED("user_unknown"),
+ /** Passwords didn't match, check them again! */
PASSWORD_MATCH_ERROR("password_error"),
+ /** You can't use your name as password, please choose another one... */
PASSWORD_IS_USERNAME_ERROR("password_error_nick"),
+ /** The chosen password isn't safe, please choose another one... */
PASSWORD_UNSAFE_ERROR("password_error_unsafe"),
+ /** Your password contains illegal characters. Allowed chars: REG_EX */
PASSWORD_CHARACTERS_ERROR("password_error_chars", "REG_EX"),
+ /** Your IP has been changed and your session data has expired! */
SESSION_EXPIRED("invalid_session"),
+ /** Only registered users can join the server! Please visit http://example.com to register yourself! */
MUST_REGISTER_MESSAGE("reg_only"),
+ /** You're already logged in! */
ALREADY_LOGGED_IN_ERROR("logged_in"),
+ /** Logged-out successfully! */
LOGOUT_SUCCESS("logout"),
+ /** The same username is already playing on the server! */
USERNAME_ALREADY_ONLINE_ERROR("same_nick"),
+ /** Successfully registered! */
REGISTER_SUCCESS("registered"),
+ /** Your password is too short or too long! Please try with another one! */
INVALID_PASSWORD_LENGTH("pass_len"),
+ /** Configuration and database have been reloaded correctly! */
CONFIG_RELOAD_SUCCESS("reload"),
+ /** Login timeout exceeded, you have been kicked from the server, please try again! */
LOGIN_TIMEOUT_ERROR("timeout"),
+ /** Usage: /changepassword >oldPassword> >newPassword> */
USAGE_CHANGE_PASSWORD("usage_changepassword"),
+ /** Your username is either too short or too long! */
INVALID_NAME_LENGTH("name_len"),
+ /** Your username contains illegal characters. Allowed chars: REG_EX */
INVALID_NAME_CHARACTERS("regex", "REG_EX"),
+ /** Please add your email to your account with the command "/email add >yourEmail> >confirmEmail>" */
ADD_EMAIL_MESSAGE("add_email"),
+ /** Forgot your password? Please use the command "/email recovery >yourEmail>" */
FORGOT_PASSWORD_MESSAGE("recovery_email"),
+ /** To login you have to solve a captcha code, please use the command "/captcha >theCaptcha>" */
USAGE_CAPTCHA("usage_captcha", ""),
+ /** Wrong captcha, please type "/captcha THE_CAPTCHA" into the chat! */
CAPTCHA_WRONG_ERROR("wrong_captcha", "THE_CAPTCHA"),
+ /** Captcha code solved correctly! */
CAPTCHA_SUCCESS("valid_captcha"),
+ /** A VIP player has joined the server when it was full! */
KICK_FOR_VIP("kick_forvip"),
+ /** The server is full, try again later! */
KICK_FULL_SERVER("kick_fullserver"),
+ /** Usage: /email add >email> >confirmEmail> */
USAGE_ADD_EMAIL("usage_email_add"),
+ /** Usage: /email change >oldEmail> >newEmail> */
USAGE_CHANGE_EMAIL("usage_email_change"),
+ /** Usage: /email recovery >Email> */
USAGE_RECOVER_EMAIL("usage_email_recovery"),
+ /** Invalid new email, try again! */
INVALID_NEW_EMAIL("new_email_invalid"),
+ /** Invalid old email, try again! */
INVALID_OLD_EMAIL("old_email_invalid"),
+ /** Invalid email address, try again! */
INVALID_EMAIL("email_invalid"),
+ /** Email address successfully added to your account! */
EMAIL_ADDED_SUCCESS("email_added"),
+ /** Please confirm your email address! */
CONFIRM_EMAIL_MESSAGE("email_confirm"),
+ /** Email address changed correctly! */
EMAIL_CHANGED_SUCCESS("email_changed"),
+ /** Your current email address is: %email */
EMAIL_SHOW("email_show", "%email"),
+ /** You currently don't have email address associated with this account. */
SHOW_NO_EMAIL("show_no_email"),
+ /** Recovery email sent successfully! Please check your email inbox! */
RECOVERY_EMAIL_SENT_MESSAGE("email_send"),
+ /** A recovery email was already sent! You can discard it and send a new one using the command below: */
RECOVERY_EMAIL_ALREADY_SENT_MESSAGE("email_exists"),
+ /** Your country is banned from this server! */
COUNTRY_BANNED_ERROR("country_banned"),
+ /** [AntiBotService] AntiBot enabled due to the huge number of connections! */
ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"),
+ /** [AntiBotService] AntiBot disabled after %m minutes! */
ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"),
+ /** The email address is already being used */
EMAIL_ALREADY_USED_ERROR("email_already_used"),
+ /** Your secret code is %code. You can scan it from here %url */
TWO_FACTOR_CREATE("two_factor_create", "%code", "%url"),
+ /** You are not the owner of this account. Please choose another name! */
NOT_OWNER_ERROR("not_owner_error"),
+ /** You should join using username %valid, not %invalid. */
INVALID_NAME_CASE("invalid_name_case", "%valid", "%invalid"),
+ /** You have been temporarily banned for failing to log in too many times. */
TEMPBAN_MAX_LOGINS("tempban_max_logins"),
+ /** You own %count accounts: */
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
+ /** The player %name has %count accounts: */
ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"),
+ /** An admin just registered you; please log in again */
KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"),
+ /** Error: not all required settings are set for sending emails. Please contact an admin. */
INCOMPLETE_EMAIL_SETTINGS("incomplete_email_settings"),
+ /** The email could not be sent. Please contact an administrator. */
+ EMAIL_SEND_FAILURE("email_send_failure"),
+
+ /** A recovery code to reset your password has been sent to your email. */
RECOVERY_CODE_SENT("recovery_code_sent"),
+ /** The recovery code is not correct! Use /email recovery [email] to generate a new one */
INCORRECT_RECOVERY_CODE("recovery_code_incorrect");
private String key;
diff --git a/src/main/java/fr/xephi/authme/output/Log4JFilter.java b/src/main/java/fr/xephi/authme/output/Log4JFilter.java
index 90b9f0fb6..1d044e184 100644
--- a/src/main/java/fr/xephi/authme/output/Log4JFilter.java
+++ b/src/main/java/fr/xephi/authme/output/Log4JFilter.java
@@ -12,14 +12,9 @@ import org.apache.logging.log4j.message.Message;
*
* @author Xephi59
*/
-@SuppressWarnings("serial")
public class Log4JFilter extends AbstractFilter {
- /**
- * Constructor.
- */
- public Log4JFilter() {
- }
+ private static final long serialVersionUID = -5594073755007974254L;
/**
* Validates a Message instance and returns the {@link Result} value
diff --git a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
index fb4bff486..537c3ebc5 100644
--- a/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/AuthGroupHandler.java
@@ -10,6 +10,7 @@ import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.entity.Player;
+import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.Arrays;
@@ -31,7 +32,8 @@ public class AuthGroupHandler implements Reloadable {
private String unregisteredGroup;
private String registeredGroup;
- AuthGroupHandler() { }
+ AuthGroupHandler() {
+ }
/**
* Set the group of a player, by its AuthMe group type.
@@ -114,6 +116,7 @@ public class AuthGroupHandler implements Reloadable {
}
@Override
+ @PostConstruct
public void reload() {
unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);
diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
index c0c6981aa..29406be6c 100644
--- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
+++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
@@ -78,12 +78,12 @@ public class PermissionsManager implements Reloadable {
if (handler != null) {
// Show a success message and return
this.handler = handler;
- ConsoleLogger.info("Hooked into " + type.getName() + "!");
+ ConsoleLogger.info("Hooked into " + type.getDisplayName() + "!");
return;
}
} catch (Exception ex) {
// An error occurred, show a warning message
- ConsoleLogger.logException("Error while hooking into " + type.getName(), ex);
+ ConsoleLogger.logException("Error while hooking into " + type.getDisplayName(), ex);
}
}
@@ -101,7 +101,7 @@ public class PermissionsManager implements Reloadable {
// Make sure the plugin is enabled before hooking
if (!plugin.isEnabled()) {
- ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
+ ConsoleLogger.info("Not hooking into " + type.getDisplayName() + " because it's disabled!");
return null;
}
@@ -414,7 +414,7 @@ public class PermissionsManager implements Reloadable {
*/
public boolean setGroups(Player player, List groupNames) {
// If no permissions system is used or if there's no group supplied, return false
- if (!isEnabled() || groupNames.size() <= 0)
+ if (!isEnabled() || groupNames.isEmpty())
return false;
// Set the main group
diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java b/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java
index 1410bc668..72a0753cb 100644
--- a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java
+++ b/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java
@@ -33,21 +33,21 @@ public enum PermissionsSystemType {
/**
* The display name of the permissions system.
*/
- public String name;
+ private String displayName;
/**
* The name of the permissions system plugin.
*/
- public String pluginName;
+ private String pluginName;
/**
* Constructor for PermissionsSystemType.
*
- * @param name Display name of the permissions system.
+ * @param displayName Display name of the permissions system.
* @param pluginName Name of the plugin.
*/
- PermissionsSystemType(String name, String pluginName) {
- this.name = name;
+ PermissionsSystemType(String displayName, String pluginName) {
+ this.displayName = displayName;
this.pluginName = pluginName;
}
@@ -56,8 +56,8 @@ public enum PermissionsSystemType {
*
* @return Display name.
*/
- public String getName() {
- return this.name;
+ public String getDisplayName() {
+ return this.displayName;
}
/**
@@ -76,7 +76,7 @@ public enum PermissionsSystemType {
*/
@Override
public String toString() {
- return getName();
+ return getDisplayName();
}
/**
diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
index 0820be011..aaeb0eea3 100644
--- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
+++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
@@ -17,7 +17,7 @@ public enum PlayerStatePermission implements PermissionNode {
BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY),
/**
- * Permission node to identify VIP users.
+ * When the server is full and someone with this permission joins the server, someone will be kicked.
*/
IS_VIP("authme.vip", DefaultPermission.OP_ONLY),
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
index 983e42e27..9f52214b9 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/BPermissionsHandler.java
@@ -55,7 +55,7 @@ public class BPermissionsHandler implements PermissionHandler {
List groups = getGroups(player);
// Make sure there is any group available, or return null
- if (groups.size() == 0)
+ if (groups.isEmpty())
return null;
// Return the first group
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
index 344e0aec5..e8e8a21e5 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsBukkitHandler.java
@@ -54,7 +54,7 @@ public class PermissionsBukkitHandler implements PermissionHandler {
List groups = getGroups(player);
// Make sure there is any group available, or return null
- if (groups.size() == 0)
+ if (groups.isEmpty())
return null;
// Return the first group
diff --git a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
index e3e03ee32..b11d00003 100644
--- a/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
+++ b/src/main/java/fr/xephi/authme/permission/handlers/PermissionsExHandler.java
@@ -77,7 +77,7 @@ public class PermissionsExHandler implements PermissionHandler {
PermissionUser user = permissionManager.getUser(player);
List groups = user.getParentIdentifiers(null);
- if (groups.size() == 0)
+ if (groups.isEmpty())
return null;
return groups.get(0);
diff --git a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java b/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
index 12471b0ea..2a3fa1755 100644
--- a/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
+++ b/src/main/java/fr/xephi/authme/process/changepassword/AsyncChangePassword.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.entity.Player;
@@ -19,7 +19,7 @@ public class AsyncChangePassword implements AsynchronousProcess {
private DataSource dataSource;
@Inject
- private ProcessService processService;
+ private CommonService commonService;
@Inject
private PasswordSecurity passwordSecurity;
@@ -27,7 +27,8 @@ public class AsyncChangePassword implements AsynchronousProcess {
@Inject
private PlayerCache playerCache;
- AsyncChangePassword() { }
+ AsyncChangePassword() {
+ }
public void changePassword(final Player player, String oldPassword, String newPassword) {
@@ -38,15 +39,15 @@ public class AsyncChangePassword implements AsynchronousProcess {
auth.setPassword(hashedPassword);
if (!dataSource.updatePassword(auth)) {
- processService.send(player, MessageKey.ERROR);
+ commonService.send(player, MessageKey.ERROR);
return;
}
playerCache.updatePlayer(auth);
- processService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
+ commonService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password");
} else {
- processService.send(player, MessageKey.WRONG_PASSWORD);
+ commonService.send(player, MessageKey.WRONG_PASSWORD);
}
}
}
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
index 5a8a8e90c..fb5c6c9c3 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
@@ -6,7 +6,8 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
+import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player;
@@ -18,7 +19,7 @@ import javax.inject.Inject;
public class AsyncAddEmail implements AsynchronousProcess {
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private DataSource dataSource;
@@ -26,6 +27,9 @@ public class AsyncAddEmail implements AsynchronousProcess {
@Inject
private PlayerCache playerCache;
+ @Inject
+ private ValidationService validationService;
+
AsyncAddEmail() { }
public void addEmail(Player player, String email) {
@@ -37,9 +41,9 @@ public class AsyncAddEmail implements AsynchronousProcess {
if (currentEmail != null && !"your@email.com".equals(currentEmail)) {
service.send(player, MessageKey.USAGE_CHANGE_EMAIL);
- } else if (!service.validateEmail(email)) {
+ } else if (!validationService.validateEmail(email)) {
service.send(player, MessageKey.INVALID_EMAIL);
- } else if (!service.isEmailFreeForRegistration(email, player)) {
+ } else if (!validationService.isEmailFreeForRegistration(email, player)) {
service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else {
auth.setEmail(email);
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
index 6bc83106b..d876ab584 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
@@ -5,7 +5,8 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
+import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player;
@@ -17,7 +18,7 @@ import javax.inject.Inject;
public class AsyncChangeEmail implements AsynchronousProcess {
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PlayerCache playerCache;
@@ -25,6 +26,9 @@ public class AsyncChangeEmail implements AsynchronousProcess {
@Inject
private DataSource dataSource;
+ @Inject
+ private ValidationService validationService;
+
AsyncChangeEmail() { }
public void changeEmail(Player player, String oldEmail, String newEmail) {
@@ -35,11 +39,11 @@ public class AsyncChangeEmail implements AsynchronousProcess {
if (currentEmail == null) {
service.send(player, MessageKey.USAGE_ADD_EMAIL);
- } else if (newEmail == null || !service.validateEmail(newEmail)) {
+ } else if (newEmail == null || !validationService.validateEmail(newEmail)) {
service.send(player, MessageKey.INVALID_NEW_EMAIL);
} else if (!oldEmail.equals(currentEmail)) {
service.send(player, MessageKey.INVALID_OLD_EMAIL);
- } else if (!service.isEmailFreeForRegistration(newEmail, player)) {
+ } else if (!validationService.isEmailFreeForRegistration(newEmail, player)) {
service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else {
saveNewEmail(auth, player, newEmail);
diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
index 89e7a671e..dab9cdc2c 100644
--- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
+++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
@@ -13,8 +13,9 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.login.AsynchronousLogin;
+import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
@@ -22,9 +23,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.PlayerUtils;
-import org.apache.commons.lang.reflect.MethodUtils;
import org.bukkit.GameMode;
-import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -39,9 +38,6 @@ import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
*/
public class AsynchronousJoin implements AsynchronousProcess {
- private static final boolean DISABLE_COLLISIONS = MethodUtils
- .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null;
-
@Inject
private AuthMe plugin;
@@ -49,7 +45,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
private DataSource database;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PlayerCache playerCache;
@@ -72,23 +68,20 @@ public class AsynchronousJoin implements AsynchronousProcess {
@Inject
private AsynchronousLogin asynchronousLogin;
+ @Inject
+ private CommandManager commandManager;
+
AsynchronousJoin() {
}
-
public void processJoin(final Player player) {
final String name = player.getName().toLowerCase();
final String ip = PlayerUtils.getPlayerIp(player);
- if (isPlayerUnrestricted(name)) {
+ if (service.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name)) {
return;
}
- // Prevent player collisions in 1.9
- if (DISABLE_COLLISIONS) {
- player.setCollidable(false);
- }
-
if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE)
&& !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) {
bukkitService.runTask(() -> player.setGameMode(GameMode.SURVIVAL));
@@ -115,7 +108,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
return;
}
-
final boolean isAuthAvailable = database.isAuthAvailable(name);
if (isAuthAvailable) {
@@ -162,26 +154,23 @@ public class AsynchronousJoin implements AsynchronousProcess {
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
- bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
- @Override
- public void run() {
- player.setOp(false);
- if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
- && service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
- player.setFlySpeed(0.0f);
- player.setWalkSpeed(0.0f);
- }
- player.setNoDamageTicks(registrationTimeout);
- if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
- player.performCommand("motd");
- }
- if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
- // Allow infinite blindness effect
- int blindTimeOut = (registrationTimeout <= 0) ? 99999 : registrationTimeout;
- player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blindTimeOut, 2));
- }
+ bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
+ player.setOp(false);
+ if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
+ && service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
+ player.setFlySpeed(0.0f);
+ player.setWalkSpeed(0.0f);
}
-
+ player.setNoDamageTicks(registrationTimeout);
+ if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
+ player.performCommand("motd");
+ }
+ if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
+ // Allow infinite blindness effect
+ int blindTimeOut = (registrationTimeout <= 0) ? 99999 : registrationTimeout;
+ player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blindTimeOut, 2));
+ }
+ commandManager.runCommandsOnJoin(player);
});
// Timeout and message task
@@ -189,10 +178,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
limboPlayerTaskManager.registerMessageTask(name, isAuthAvailable);
}
- private boolean isPlayerUnrestricted(String name) {
- return service.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name);
- }
-
/**
* Returns whether the name is restricted based on the restriction settings.
*
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 f9843a169..80b12a200 100644
--- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
@@ -16,7 +16,7 @@ import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.properties.DatabaseSettings;
@@ -44,7 +44,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
private DataSource dataSource;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PermissionsManager permissionsManager;
@@ -224,7 +224,11 @@ public class AsynchronousLogin implements AsynchronousProcess {
player.setNoDamageTicks(0);
service.send(player, MessageKey.LOGIN_SUCCESS);
- displayOtherAccounts(auth, player);
+
+ // Other auths
+ List auths = dataSource.getAllAuthsByIp(auth.getIp());
+ runCommandOtherAccounts(auths, player, auth.getIp());
+ displayOtherAccounts(auths, player);
final String email = auth.getEmail();
if (service.getProperty(EmailSettings.RECALL_PLAYERS)
@@ -252,12 +256,29 @@ public class AsynchronousLogin implements AsynchronousProcess {
}
}
- private void displayOtherAccounts(PlayerAuth auth, Player player) {
- if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auth == null) {
+ private void runCommandOtherAccounts(List auths, Player player, String ip) {
+ int threshold = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD_THRESHOLD);
+ String command = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD);
+
+ if(threshold < 2 || command.isEmpty()) {
+ return;
+ }
+
+ if (auths.size() < threshold) {
+ return;
+ }
+
+ bukkitService.dispatchConsoleCommand(command
+ .replaceAll("%playername%", player.getName())
+ .replaceAll("%playerip%", ip)
+ );
+ }
+
+ private void displayOtherAccounts(List auths, Player player) {
+ if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS)) {
return;
}
- List auths = dataSource.getAllAuthsByIp(auth.getIp());
if (auths.size() <= 1) {
return;
}
diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
index a31f4d28f..d64bda776 100644
--- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java
@@ -8,38 +8,31 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.LoginEvent;
import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.listener.PlayerListener;
-import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess;
-import fr.xephi.authme.service.BungeeService;
-import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.service.TeleportationService;
-import org.apache.commons.lang.reflect.MethodUtils;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.commandconfig.CommandManager;
+import fr.xephi.authme.settings.properties.RegistrationSettings;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.Bukkit;
-import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
-import static fr.xephi.authme.settings.properties.PluginSettings.KEEP_COLLISIONS_DISABLED;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
public class ProcessSyncPlayerLogin implements SynchronousProcess {
- private static final boolean RESTORE_COLLISIONS = MethodUtils
- .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null;
-
@Inject
private AuthMe plugin;
@Inject
private BungeeService bungeeService;
- @Inject
- private ProcessService service;
-
@Inject
private LimboCache limboCache;
@@ -55,6 +48,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private DataSource dataSource;
+ @Inject
+ private CommandManager commandManager;
+
+ @Inject
+ private Settings settings;
+
ProcessSyncPlayerLogin() {
}
@@ -66,16 +65,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
}
}
- private void forceCommands(Player player) {
- for (String command : service.getProperty(RegistrationSettings.FORCE_COMMANDS)) {
- player.performCommand(command.replace("%p", player.getName()));
- }
- for (String command : service.getProperty(RegistrationSettings.FORCE_COMMANDS_AS_CONSOLE)) {
- Bukkit.getServer().dispatchCommand(
- Bukkit.getServer().getConsoleSender(), command.replace("%p", player.getName()));
- }
- }
-
public void processPlayerLogin(Player player) {
final String name = player.getName().toLowerCase();
@@ -88,11 +77,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// because LimboCache#restoreData teleport player to last location.
}
- if (RESTORE_COLLISIONS && !service.getProperty(KEEP_COLLISIONS_DISABLED)) {
- player.setCollidable(true);
- }
-
- if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
+ if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
restoreInventory(player);
}
@@ -100,19 +85,16 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
teleportationService.teleportOnLogin(player, auth, limbo);
// We can now display the join message (if delayed)
- String jm = PlayerListener.joinMessage.get(name);
- if (jm != null) {
- if (!jm.isEmpty()) {
- for (Player p : bukkitService.getOnlinePlayers()) {
- if (p.isOnline()) {
- p.sendMessage(jm);
- }
+ String joinMessage = PlayerListener.joinMessage.remove(name);
+ if (!StringUtils.isEmpty(joinMessage)) {
+ for (Player p : bukkitService.getOnlinePlayers()) {
+ if (p.isOnline()) {
+ p.sendMessage(joinMessage);
}
}
- PlayerListener.joinMessage.remove(name);
}
- if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
+ if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
player.removePotionEffect(PotionEffectType.BLINDNESS);
}
@@ -121,20 +103,20 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
player.saveData();
// Login is done, display welcome message
- if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
- if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
- for (String s : service.getSettings().getWelcomeMessage()) {
+ if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
+ if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
+ for (String s : settings.getWelcomeMessage()) {
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
}
} else {
- for (String s : service.getSettings().getWelcomeMessage()) {
+ for (String s : settings.getWelcomeMessage()) {
player.sendMessage(plugin.replaceAllInfo(s, player));
}
}
}
// Login is now finished; we can force all commands
- forceCommands(player);
+ commandManager.runCommandsOnLogin(player);
// Send Bungee stuff. The service will check if it is enabled or not.
bungeeService.connectPlayer(player);
diff --git a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
index 7374d7389..efd3066aa 100644
--- a/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
+++ b/src/main/java/fr/xephi/authme/process/logout/AsynchronousLogout.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
@@ -19,7 +19,7 @@ public class AsynchronousLogout implements AsynchronousProcess {
private DataSource database;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PlayerCache playerCache;
diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
index 72ff935e0..17710df45 100644
--- a/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
+++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSynchronousPlayerLogout.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.events.LogoutEvent;
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
@@ -25,7 +25,7 @@ import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private BukkitService bukkitService;
diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
index c8f63bbd4..d34cbde07 100644
--- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
+++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
@@ -7,7 +7,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.RestrictionSettings;
@@ -27,7 +27,7 @@ public class AsynchronousQuit implements AsynchronousProcess {
private DataSource database;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PlayerCache playerCache;
diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
index 627a993b6..02ef0ce14 100644
--- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
@@ -7,7 +7,7 @@ import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.HashAlgorithm;
@@ -51,7 +51,7 @@ public class AsyncRegister implements AsynchronousProcess {
@Inject
private PasswordSecurity passwordSecurity;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
@@ -148,8 +148,12 @@ public class AsyncRegister implements AsynchronousProcess {
}
database.updateEmail(auth);
database.updateSession(auth);
- sendMailSsl.sendPasswordMail(name, email, password);
- syncProcessManager.processSyncEmailRegister(player);
+ boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, password);
+ if (couldSendMail) {
+ syncProcessManager.processSyncEmailRegister(player);
+ } else {
+ service.send(player, MessageKey.EMAIL_SEND_FAILURE);
+ }
}
private void passwordRegister(final Player player, String password, boolean autoLogin) {
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
index de77a17d0..aea1b4be8 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
@@ -3,7 +3,7 @@ package fr.xephi.authme.process.register;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager;
@@ -16,13 +16,13 @@ import javax.inject.Inject;
public class ProcessSyncEmailRegister implements SynchronousProcess {
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private LimboPlayerTaskManager limboPlayerTaskManager;
- ProcessSyncEmailRegister() { }
-
+ ProcessSyncEmailRegister() {
+ }
public void processEmailRegister(Player player) {
final String name = player.getName().toLowerCase();
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
index cc190a3c5..fae428d00 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
@@ -4,15 +4,15 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BungeeService;
+import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager;
import fr.xephi.authme.util.PlayerUtils;
-import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@@ -25,7 +25,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
private BungeeService bungeeService;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private LimboCache limboCache;
@@ -33,17 +33,10 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
@Inject
private LimboPlayerTaskManager limboPlayerTaskManager;
- ProcessSyncPasswordRegister() {
- }
+ @Inject
+ private CommandManager commandManager;
- private void forceCommands(Player player) {
- for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS)) {
- player.performCommand(command.replace("%p", player.getName()));
- }
- for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS_AS_CONSOLE)) {
- Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(),
- command.replace("%p", player.getName()));
- }
+ ProcessSyncPasswordRegister() {
}
/**
@@ -83,7 +76,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
}
// Register is now finished; we can force all commands
- forceCommands(player);
+ commandManager.runCommandsOnRegister(player);
// Request login after registration
if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) {
diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
index 7d63d0555..764e56768 100644
--- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
+++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
@@ -9,7 +9,7 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupHandler;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.AsynchronousProcess;
-import fr.xephi.authme.process.ProcessService;
+import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
@@ -31,7 +31,7 @@ public class AsynchronousUnregister implements AsynchronousProcess {
private DataSource dataSource;
@Inject
- private ProcessService service;
+ private CommonService service;
@Inject
private PasswordSecurity passwordSecurity;
diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
index 7bb5681ff..732582e03 100644
--- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
+++ b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java
@@ -3,8 +3,7 @@ package fr.xephi.authme.security;
import fr.xephi.authme.security.crypts.EncryptionMethod;
/**
- * The list of hash algorithms supported by AuthMe. The linked {@link EncryptionMethod} implementation
- * must be able to be instantiated with the default constructor.
+ * Hash algorithms supported by AuthMe.
*/
public enum HashAlgorithm {
@@ -18,8 +17,8 @@ public enum HashAlgorithm {
MD5(fr.xephi.authme.security.crypts.MD5.class),
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
- PBKDF2(fr.xephi.authme.security.crypts.CryptPBKDF2.class),
- PBKDF2DJANGO(fr.xephi.authme.security.crypts.CryptPBKDF2Django.class),
+ PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
+ PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
@Deprecated
diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
index 521decfae..246070586 100644
--- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
+++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
@@ -6,12 +6,14 @@ import fr.xephi.authme.events.PasswordEncryptionEvent;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashedPassword;
+import fr.xephi.authme.settings.EnumSetProperty;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.plugin.PluginManager;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import java.util.Collection;
/**
* Manager class for password-related operations.
@@ -31,7 +33,7 @@ public class PasswordSecurity implements Reloadable {
private Injector injector;
private HashAlgorithm algorithm;
- private boolean supportOldAlgorithm;
+ private Collection legacyAlgorithms;
/**
* Load or reload the configuration.
@@ -40,7 +42,8 @@ public class PasswordSecurity implements Reloadable {
@Override
public void reload() {
this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
- this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH);
+ // TODO #1014: Need to cast to specific type because ConfigMe ignores fields of child Property types
+ this.legacyAlgorithms = ((EnumSetProperty) SecuritySettings.LEGACY_HASHES).asEnumSet(settings);
}
/**
@@ -83,7 +86,7 @@ public class PasswordSecurity implements Reloadable {
EncryptionMethod method = initializeEncryptionMethodWithEvent(algorithm, playerName);
String playerLowerCase = playerName.toLowerCase();
return methodMatches(method, password, hashedPassword, playerLowerCase)
- || supportOldAlgorithm && compareWithAllEncryptionMethods(password, hashedPassword, playerLowerCase);
+ || compareWithLegacyHashes(password, hashedPassword, playerLowerCase);
}
/**
@@ -97,14 +100,12 @@ public class PasswordSecurity implements Reloadable {
*
* @return True if there was a password match with another encryption method, false otherwise
*/
- private boolean compareWithAllEncryptionMethods(String password, HashedPassword hashedPassword, String playerName) {
- for (HashAlgorithm algorithm : HashAlgorithm.values()) {
- if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
- EncryptionMethod method = initializeEncryptionMethod(algorithm);
- if (methodMatches(method, password, hashedPassword, playerName)) {
- hashPasswordForNewAlgorithm(password, playerName);
- return true;
- }
+ private boolean compareWithLegacyHashes(String password, HashedPassword hashedPassword, String playerName) {
+ for (HashAlgorithm algorithm : legacyAlgorithms) {
+ EncryptionMethod method = initializeEncryptionMethod(algorithm);
+ if (methodMatches(method, password, hashedPassword, playerName)) {
+ hashPasswordForNewAlgorithm(password, playerName);
+ return true;
}
}
return false;
diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java b/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java
deleted file mode 100644
index 57c13ee6c..000000000
--- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package fr.xephi.authme.security.crypts;
-
-import fr.xephi.authme.security.crypts.description.Recommendation;
-import fr.xephi.authme.security.crypts.description.Usage;
-import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
-import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
-
-import java.util.Arrays;
-
-@Recommendation(Usage.DOES_NOT_WORK)
-public class CryptPBKDF2 extends HexSaltedMethod {
-
- @Override
- public String computeHash(String password, String salt, String name) {
- String result = "pbkdf2_sha256$10000$" + salt + "$";
- PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000);
- PBKDF2Engine engine = new PBKDF2Engine(params);
-
- return result + Arrays.toString(engine.deriveKey(password, 64));
- }
-
- @Override
- public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) {
- String[] line = hashedPassword.getHash().split("\\$");
- if (line.length != 4) {
- return false;
- }
- String salt = line[2];
- String derivedKey = line[3];
- PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes());
- PBKDF2Engine engine = new PBKDF2Engine(params);
- return engine.verifyKey(password);
- }
-
- @Override
- public int getSaltLength() {
- return 12;
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java b/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java
index ee7e49c79..ca72674b3 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/JOOMLA.java
@@ -4,7 +4,7 @@ import fr.xephi.authme.security.HashUtils;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.Usage;
-@Recommendation(Usage.RECOMMENDED)
+@Recommendation(Usage.ACCEPTABLE)
public class JOOMLA extends HexSaltedMethod {
@Override
diff --git a/src/main/java/fr/xephi/authme/security/crypts/PLAINTEXT.java b/src/main/java/fr/xephi/authme/security/crypts/PLAINTEXT.java
index dc2cb3b40..a294ca917 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/PLAINTEXT.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/PLAINTEXT.java
@@ -1,5 +1,10 @@
package fr.xephi.authme.security.crypts;
+/**
+ * Plaintext password storage.
+ *
+ * @deprecated Using this is no longer supported. AuthMe will migrate to SHA256 on startup.
+ */
@Deprecated
public class PLAINTEXT extends UnsaltedMethod {
diff --git a/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
new file mode 100644
index 000000000..5367a2a12
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
@@ -0,0 +1,60 @@
+package fr.xephi.authme.security.crypts;
+
+import de.rtner.misc.BinTools;
+import de.rtner.security.auth.spi.PBKDF2Engine;
+import de.rtner.security.auth.spi.PBKDF2Parameters;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.security.crypts.description.Recommendation;
+import fr.xephi.authme.security.crypts.description.Usage;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.SecuritySettings;
+
+import javax.inject.Inject;
+
+@Recommendation(Usage.RECOMMENDED)
+public class Pbkdf2 extends HexSaltedMethod {
+
+ private static final int DEFAULT_ROUNDS = 10_000;
+ private int numberOfRounds;
+
+ @Inject
+ Pbkdf2(Settings settings) {
+ int configuredRounds = settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS);
+ this.numberOfRounds = configuredRounds > 0 ? configuredRounds : DEFAULT_ROUNDS;
+ }
+
+ @Override
+ public String computeHash(String password, String salt, String name) {
+ String result = "pbkdf2_sha256$" + numberOfRounds + "$" + salt + "$";
+ PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), numberOfRounds);
+ PBKDF2Engine engine = new PBKDF2Engine(params);
+
+ return result + BinTools.bin2hex(engine.deriveKey(password, 64));
+ }
+
+ @Override
+ public boolean comparePassword(String password, HashedPassword hashedPassword, String unusedName) {
+ String[] line = hashedPassword.getHash().split("\\$");
+ if (line.length != 4) {
+ return false;
+ }
+ int iterations;
+ try {
+ iterations = Integer.parseInt(line[1]);
+ } catch (NumberFormatException e) {
+ ConsoleLogger.logException("Cannot read number of rounds for Pbkdf2", e);
+ return false;
+ }
+ String salt = line[2];
+ byte[] derivedKey = BinTools.hex2bin(line[3]);
+ PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), iterations, derivedKey);
+ PBKDF2Engine engine = new PBKDF2Engine(params);
+ return engine.verifyKey(password);
+ }
+
+ @Override
+ public int getSaltLength() {
+ return 16;
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java
similarity index 75%
rename from src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java
rename to src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java
index 79d06e0a8..93988e0d0 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/CryptPBKDF2Django.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/Pbkdf2Django.java
@@ -1,15 +1,14 @@
package fr.xephi.authme.security.crypts;
+import de.rtner.security.auth.spi.PBKDF2Engine;
+import de.rtner.security.auth.spi.PBKDF2Parameters;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
-import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
-import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
-import fr.xephi.authme.util.StringUtils;
import javax.xml.bind.DatatypeConverter;
@AsciiRestricted
-public class CryptPBKDF2Django extends HexSaltedMethod {
+public class Pbkdf2Django extends HexSaltedMethod {
private static final int DEFAULT_ITERATIONS = 24000;
@@ -19,7 +18,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), DEFAULT_ITERATIONS);
PBKDF2Engine engine = new PBKDF2Engine(params);
- return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32)));
+ return result + DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32));
}
@Override
@@ -32,8 +31,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
try {
iterations = Integer.parseInt(line[1]);
} catch (NumberFormatException e) {
- ConsoleLogger.warning("Could not read number of rounds for CryptPBKDF2Django:"
- + StringUtils.formatException(e));
+ ConsoleLogger.logException("Could not read number of rounds for Pbkdf2Django:", e);
return false;
}
String salt = line[2];
diff --git a/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java b/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java
index 186128744..f2ebf1976 100644
--- a/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java
+++ b/src/main/java/fr/xephi/authme/security/crypts/XAUTH.java
@@ -18,14 +18,14 @@ public class XAUTH extends HexSaltedMethod {
@Override
public String computeHash(String password, String salt, String name) {
String hash = getWhirlpool(salt + password).toLowerCase();
- int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
+ int saltPos = password.length() >= hash.length() ? hash.length() - 1 : password.length();
return hash.substring(0, saltPos) + salt + hash.substring(saltPos);
}
@Override
public boolean comparePassword(String password, HashedPassword hashedPassword, String playerName) {
String hash = hashedPassword.getHash();
- int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
+ int saltPos = password.length() >= hash.length() ? hash.length() - 1 : password.length();
if (saltPos + 12 > hash.length()) {
return false;
}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/BinTools.java b/src/main/java/fr/xephi/authme/security/pbkdf2/BinTools.java
deleted file mode 100644
index 34bf8aac2..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/BinTools.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-/*
- * Free auxiliary functions. Copyright 2007, 2014, Matthias Gärtner
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-/**
- * Free auxiliary functions
- *
- * @author Matthias Gärtner
- */
-public class BinTools {
- public static final String hex = "0123456789ABCDEF";
-
- /**
- * Simple binary-to-hexadecimal conversion.
- *
- * @param b
- * Input bytes. May be null.
- * @return Hexadecimal representation of b. Uppercase A-F, two characters
- * per byte. Empty string on null input.
- */
- public static String bin2hex(final byte[] b) {
- if (b == null) {
- return "";
- }
- StringBuffer sb = new StringBuffer(2 * b.length);
- for (int i = 0; i < b.length; i++) {
- int v = (256 + b[i]) % 256;
- sb.append(hex.charAt((v / 16) & 15));
- sb.append(hex.charAt((v % 16) & 15));
- }
- return sb.toString();
- }
-
- /**
- * Convert hex string to array of bytes.
- *
- * @param s
- * String containing hexadecimal digits. May be null
- * . On odd length leading zero will be assumed.
- * @return Array on bytes, non-null.
- * @throws IllegalArgumentException
- * when string contains non-hex character
- */
- public static byte[] hex2bin(final String s) {
- String m = s;
- if (s == null) {
- // Allow empty input string.
- m = "";
- } else if (s.length() % 2 != 0) {
- // Assume leading zero for odd string length
- m = "0" + s;
- }
- byte r[] = new byte[m.length() / 2];
- for (int i = 0, n = 0; i < m.length(); n++) {
- char h = m.charAt(i++);
- char l = m.charAt(i++);
- r[n] = (byte) (hex2bin(h) * 16 + hex2bin(l));
- }
- return r;
- }
-
- /**
- * Convert hex digit to numerical value.
- *
- * @param c
- * 0-9, a-f, A-F allowd.
- * @return 0-15
- * @throws IllegalArgumentException
- * on non-hex character
- */
- public static int hex2bin(char c) {
- if (c >= '0' && c <= '9') {
- return (c - '0');
- }
- if (c >= 'A' && c <= 'F') {
- return (c - 'A' + 10);
- }
- if (c >= 'a' && c <= 'f') {
- return (c - 'a' + 10);
- }
- throw new IllegalArgumentException("Input string may only contain hex digits, but found '" + c + "'");
- }
-
- public static void main(String[] args) {
- byte b[] = new byte[256];
- byte bb = 0;
- for (int i = 0; i < 256; i++) {
- b[i] = bb++;
- }
- String s = bin2hex(b);
- byte c[] = hex2bin(s);
- String t = bin2hex(c);
- if (!s.equals(t)) {
- throw new AssertionError("Mismatch");
- }
- }
-}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java b/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java
deleted file mode 100644
index 88ff11bfc..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- *
- * Default PRF implementation based on standard javax.crypt.Mac mechanisms.
- *
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * @author Matthias Gärtner
- * @version 1.0
- */
-public class MacBasedPRF implements PRF {
-
- protected Mac mac;
-
- protected int hLen;
-
- protected final String macAlgorithm;
-
- /**
- * Create Mac-based Pseudo Random Function.
- *
- * @param macAlgorithm Mac algorithm to use, i.e. HMacSHA1 or HMacMD5.
- */
- public MacBasedPRF(String macAlgorithm) {
- this.macAlgorithm = macAlgorithm;
- try {
- mac = Mac.getInstance(macAlgorithm);
- hLen = mac.getMacLength();
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- public MacBasedPRF(String macAlgorithm, String provider) {
- this.macAlgorithm = macAlgorithm;
- try {
- mac = Mac.getInstance(macAlgorithm, provider);
- hLen = mac.getMacLength();
- } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public byte[] doFinal(byte[] M) {
- byte[] r = mac.doFinal(M);
- return r;
- }
-
- @Override
- public int getHLen() {
- return hLen;
- }
-
- @Override
- public void init(byte[] P) {
- try {
- mac.init(new SecretKeySpec(P, macAlgorithm));
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java
deleted file mode 100644
index 59bc96df2..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-/**
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
PRF underlying pseudorandom function (hLen denotes the length in octets
- * of the pseudorandom function output). PRF is pluggable.
- *
- * Input:
- *
- *
P password, an octet string
- *
S salt, an octet string
- *
c iteration count, a positive integer
- *
dkLen intended length in octets of the derived key, a positive integer,
- * at most (2^32 - 1) * hLen
- *
- * Output:
- *
- *
DK derived key, a dkLen-octet string
- *
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * @author Matthias Gärtner
- * @version 1.0
- * @see RFC 2898
- */
-public class PBKDF2Engine implements PBKDF2 {
-
- protected PBKDF2Parameters parameters;
-
- protected PRF prf;
-
- /**
- * Constructor for PBKDF2 implementation object. PBKDF2 parameters must be
- * passed later.
- */
- public PBKDF2Engine() {
- this.parameters = null;
- prf = null;
- }
-
- /**
- * Constructor for PBKDF2 implementation object. PBKDF2 parameters are
- * passed so that this implementation knows iteration count, method to use
- * and String encoding.
- *
- * @param parameters Data holder for iteration count, method to use et cetera.
- */
- public PBKDF2Engine(PBKDF2Parameters parameters) {
- this.parameters = parameters;
- prf = null;
- }
-
- /**
- * Constructor for PBKDF2 implementation object. PBKDF2 parameters are
- * passed so that this implementation knows iteration count, method to use
- * and String encoding.
- *
- * @param parameters Data holder for iteration count, method to use et cetera.
- * @param prf Supply customer Pseudo Random Function.
- */
- public PBKDF2Engine(PBKDF2Parameters parameters, PRF prf) {
- this.parameters = parameters;
- this.prf = prf;
- }
-
- /**
- * Convenience client function. Convert supplied password with random 8-byte
- * salt and 1000 iterations using HMacSHA1. Assume that password is in
- * ISO-8559-1 encoding. Output result as
- * "Salt:iteration-count:PBKDF2" with binary data in hexadecimal
- * encoding.
- *
- * Example: Password "password" (without the quotes) leads to
- * 48290A0B96C426C3:1000:973899B1D4AFEB3ED371060D0797E0EE0142BD04
- *
- * @param args Supply the password as argument.
- *
- * @throws IOException an ioexception occured
- * @throws NoSuchAlgorithmException a NoSuchAlgorithmException occured
- */
- public static void main(String[] args)
- throws IOException, NoSuchAlgorithmException {
- String password = "password";
- String candidate = null;
- PBKDF2Formatter formatter = new PBKDF2HexFormatter();
-
- if (args.length >= 1) {
- password = args[0];
- }
- if (args.length >= 2) {
- candidate = args[1];
- }
- if (candidate == null) {
- // Creation mode
- SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
- byte[] salt = new byte[8];
- sr.nextBytes(salt);
- int iterations = 1000;
- PBKDF2Parameters p = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, iterations);
- PBKDF2Engine e = new PBKDF2Engine(p);
- p.setDerivedKey(e.deriveKey(password));
- candidate = formatter.toString(p);
- } else {
- // Verification mode
- PBKDF2Parameters p = new PBKDF2Parameters();
- p.setHashAlgorithm("HmacSHA1");
- p.setHashCharset("ISO-8859-1");
- if (formatter.fromString(p, candidate)) {
- throw new IllegalArgumentException("Candidate data does not have correct format (\"" + candidate + "\")");
- }
- PBKDF2Engine e = new PBKDF2Engine(p);
- boolean verifyOK = e.verifyKey(password);
- System.exit(verifyOK ? 0 : 1);
- }
- }
-
- @Override
- public byte[] deriveKey(String inputPassword) {
- return deriveKey(inputPassword, 0);
- }
-
- @Override
- public byte[] deriveKey(String inputPassword, int dkLen) {
- byte[] r = null;
- byte[] P = null;
- String charset = parameters.getHashCharset();
- if (inputPassword == null) {
- inputPassword = "";
- }
- try {
- if (charset == null) {
- P = inputPassword.getBytes();
- } else {
- P = inputPassword.getBytes(charset);
- }
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- assertPRF(P);
- if (dkLen == 0) {
- dkLen = prf.getHLen();
- }
- r = PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
- return r;
- }
-
- @Override
- public boolean verifyKey(String inputPassword) {
- byte[] referenceKey = getParameters().getDerivedKey();
- if (referenceKey == null || referenceKey.length == 0) {
- return false;
- }
- byte[] inputKey = deriveKey(inputPassword, referenceKey.length);
-
- if (inputKey == null || inputKey.length != referenceKey.length) {
- return false;
- }
- for (int i = 0; i < inputKey.length; i++) {
- if (inputKey[i] != referenceKey[i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Factory method. Default implementation is (H)MAC-based. To be overridden
- * in derived classes.
- *
- * @param P User-supplied candidate password as array of bytes.
- */
- protected void assertPRF(byte[] P) {
- if (prf == null) {
- prf = new MacBasedPRF(parameters.getHashAlgorithm());
- }
- prf.init(P);
- }
-
- @Override
- public PRF getPseudoRandomFunction() {
- return prf;
- }
-
- @Override
- public void setPseudoRandomFunction(PRF prf) {
- this.prf = prf;
- }
-
- /**
- * Core Password Based Key Derivation Function 2.
- *
- * @param prf Pseudo Random Function (i.e. HmacSHA1)
- * @param S Salt as array of bytes. null means no salt.
- * @param c Iteration count (see RFC 2898 4.2)
- * @param dkLen desired length of derived key.
- *
- * @return internal byte array * @see RFC 2898 5.2
- */
- protected byte[] PBKDF2(PRF prf, byte[] S, int c, int dkLen) {
- if (S == null) {
- S = new byte[0];
- }
- int hLen = prf.getHLen();
- int l = ceil(dkLen, hLen);
- int r = dkLen - (l - 1) * hLen;
- byte T[] = new byte[l * hLen];
- int ti_offset = 0;
- for (int i = 1; i <= l; i++) {
- _F(T, ti_offset, prf, S, c, i);
- ti_offset += hLen;
- }
- if (r < hLen) {
- // Incomplete last block
- byte DK[] = new byte[dkLen];
- System.arraycopy(T, 0, DK, 0, dkLen);
- return DK;
- }
- return T;
- }
-
- /**
- * Integer division with ceiling function.
- *
- * @param a Integer
- * @param b Integer
- *
- * @return ceil(a/b) * @see RFC 2898 5.2 Step
- * 2.
- */
- protected int ceil(int a, int b) {
- int m = 0;
- if (a % b > 0) {
- m = 1;
- }
- return a / b + m;
- }
-
- /**
- * Function F.
- *
- * @param dest Destination byte buffer
- * @param offset Offset into destination byte buffer
- * @param prf Pseudo Random Function
- * @param S Salt as array of bytes
- * @param c Iteration count
- * @param blockIndex Integer
- *
- * @see RFC 2898 5.2 Step
- * 3.
- */
- protected void _F(byte[] dest, int offset, PRF prf, byte[] S, int c,
- int blockIndex) {
- int hLen = prf.getHLen();
- byte U_r[] = new byte[hLen];
-
- // U0 = S || INT (i);
- byte U_i[] = new byte[S.length + 4];
- System.arraycopy(S, 0, U_i, 0, S.length);
- INT(U_i, S.length, blockIndex);
-
- for (int i = 0; i < c; i++) {
- U_i = prf.doFinal(U_i);
- xor(U_r, U_i);
- }
- System.arraycopy(U_r, 0, dest, offset, hLen);
- }
-
- /**
- * Block-Xor. Xor source bytes into destination byte buffer. Destination
- * buffer must be same length or less than source buffer.
- *
- * @param dest byte array
- * @param src byte array
- */
- protected void xor(byte[] dest, byte[] src) {
- for (int i = 0; i < dest.length; i++) {
- dest[i] ^= src[i];
- }
- }
-
- /**
- * Four-octet encoding of the integer i, most significant octet first.
- *
- * @param dest byte array
- * @param offset Integer
- * @param i Integer
- *
- * @see RFC 2898 5.2 Step
- * 3.
- */
- protected void INT(byte[] dest, int offset, int i) {
- dest[offset] = (byte) (i / (256 * 256 * 256));
- dest[offset + 1] = (byte) (i / (256 * 256));
- dest[offset + 2] = (byte) (i / (256));
- dest[offset + 3] = (byte) (i);
- }
-
- @Override
- public PBKDF2Parameters getParameters() {
- return parameters;
- }
-
- @Override
- public void setParameters(PBKDF2Parameters parameters) {
- this.parameters = parameters;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Formatter.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Formatter.java
deleted file mode 100644
index 3916d1c03..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Formatter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-/**
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * @author Matthias Gärtner
- * @version 1.0
- */
-public interface PBKDF2Formatter {
-
- /**
- * Convert parameters to String.
- *
- * @param p Parameters object to output.
- *
- * @return String representation
- */
- String toString(PBKDF2Parameters p);
-
- /**
- * Convert String to parameters. Depending on actual implementation, it may
- * be required to set further fields externally.
- *
- * @param s String representation of parameters to decode.
- * @param p PBKDF2Parameters
- *
- * @return false syntax OK, true some syntax
- * issue.
- */
- boolean fromString(PBKDF2Parameters p, String s);
-}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2HexFormatter.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2HexFormatter.java
deleted file mode 100644
index 54544a4c2..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2HexFormatter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-/**
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Parameter data holder for PBKDF2 configuration.
- *
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * @author Matthias Gärtner
- * @version 1.0
- */
-public class PBKDF2Parameters {
-
- protected byte[] salt;
-
- protected int iterationCount;
-
- protected String hashAlgorithm;
-
- protected String hashCharset;
-
- /**
- * The derived key is actually only a convenience to store a reference
- * derived key. It is not used during computation.
- */
- protected byte[] derivedKey;
-
- /**
- * Constructor. Defaults to null for byte arrays, UTF-8 as
- * character set and 1000 for iteration count.
- */
- public PBKDF2Parameters() {
- this.hashAlgorithm = null;
- this.hashCharset = "UTF-8";
- this.salt = null;
- this.iterationCount = 1000;
- this.derivedKey = null;
- }
-
- /**
- * Constructor.
- *
- * @param hashAlgorithm for example HMacSHA1 or HMacMD5
- * @param hashCharset for example UTF-8
- * @param salt Salt as byte array, may be null (not recommended)
- * @param iterationCount Number of iterations to execute. Recommended value 1000.
- */
- public PBKDF2Parameters(String hashAlgorithm, String hashCharset,
- byte[] salt, int iterationCount) {
- this.hashAlgorithm = hashAlgorithm;
- this.hashCharset = hashCharset;
- this.salt = salt;
- this.iterationCount = iterationCount;
- this.derivedKey = null;
- }
-
- /**
- * Constructor.
- *
- * @param hashAlgorithm for example HMacSHA1 or HMacMD5
- * @param hashCharset for example UTF-8
- * @param salt Salt as byte array, may be null (not recommended)
- * @param iterationCount Number of iterations to execute. Recommended value 1000.
- * @param derivedKey Convenience data holder, not used during computation.
- */
- public PBKDF2Parameters(String hashAlgorithm, String hashCharset,
- byte[] salt, int iterationCount, byte[] derivedKey) {
- this.hashAlgorithm = hashAlgorithm;
- this.hashCharset = hashCharset;
- this.salt = salt;
- this.iterationCount = iterationCount;
- this.derivedKey = derivedKey;
- }
-
- public int getIterationCount() {
- return iterationCount;
- }
-
- public void setIterationCount(int iterationCount) {
- this.iterationCount = iterationCount;
- }
-
- public byte[] getSalt() {
- return salt;
- }
-
- public void setSalt(byte[] salt) {
- this.salt = salt;
- }
-
- public byte[] getDerivedKey() {
- return derivedKey;
- }
-
- public void setDerivedKey(byte[] derivedKey) {
- this.derivedKey = derivedKey;
- }
-
- public String getHashAlgorithm() {
- return hashAlgorithm;
- }
-
- public void setHashAlgorithm(String hashAlgorithm) {
- this.hashAlgorithm = hashAlgorithm;
- }
-
- public String getHashCharset() {
- return hashCharset;
- }
-
- public void setHashCharset(String hashCharset) {
- this.hashCharset = hashCharset;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PRF.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PRF.java
deleted file mode 100644
index af40e171d..000000000
--- a/src/main/java/fr/xephi/authme/security/pbkdf2/PRF.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package fr.xephi.authme.security.pbkdf2;
-
-/**
- *
- * A free Java implementation of Password Based Key Derivation Function 2 as
- * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner
- *
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version.
- *
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * @author Matthias Gärtner
- * @version 1.0
- */
-public interface PRF {
-
- /**
- * Initialize this instance with the user-supplied password.
- *
- * @param P The password supplied as array of bytes. It is the caller's
- * task to convert String passwords to bytes as appropriate.
- */
- void init(byte[] P);
-
- /**
- * Pseudo Random Function
- *
- * @param M Input data/message etc. Together with any data supplied during
- * initilization.
- *
- * @return Random bytes of hLen length.
- */
- byte[] doFinal(byte[] M);
-
- /**
- * Query block size of underlying algorithm/mechanism.
- *
- * @return block size
- */
- int getHLen();
-}
diff --git a/src/main/java/fr/xephi/authme/service/AntiBotService.java b/src/main/java/fr/xephi/authme/service/AntiBotService.java
index 24118d40c..91f80041d 100644
--- a/src/main/java/fr/xephi/authme/service/AntiBotService.java
+++ b/src/main/java/fr/xephi/authme/service/AntiBotService.java
@@ -7,10 +7,11 @@ import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
-import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import javax.inject.Inject;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.concurrent.CopyOnWriteArrayList;
import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE;
@@ -25,18 +26,18 @@ public class AntiBotService implements SettingsDependent {
private final Messages messages;
private final PermissionsManager permissionsManager;
private final BukkitService bukkitService;
-
+ private final CopyOnWriteArrayList antibotKicked = new CopyOnWriteArrayList<>();
// Settings
private int duration;
private int sensibility;
private int delay;
-
+ private int interval;
// Service status
private AntiBotStatus antiBotStatus;
private boolean startup;
private BukkitTask disableTask;
- private int antibotPlayers;
- private final CopyOnWriteArrayList antibotKicked = new CopyOnWriteArrayList<>();
+ private Instant lastFlaggedJoin;
+ private int flagged = 0;
@Inject
AntiBotService(Settings settings, Messages messages, PermissionsManager permissionsManager,
@@ -47,7 +48,7 @@ public class AntiBotService implements SettingsDependent {
this.bukkitService = bukkitService;
// Initial status
disableTask = null;
- antibotPlayers = 0;
+ flagged = 0;
antiBotStatus = AntiBotStatus.DISABLED;
startup = true;
// Load settings and start if required
@@ -60,6 +61,7 @@ public class AntiBotService implements SettingsDependent {
duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION);
sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY);
delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY);
+ interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL);
// Stop existing protection
stopProtection();
@@ -71,15 +73,10 @@ public class AntiBotService implements SettingsDependent {
}
// Bot activation task
- Runnable enableTask = new Runnable() {
- @Override
- public void run() {
- antiBotStatus = AntiBotStatus.LISTENING;
- }
- };
+ Runnable enableTask = () -> antiBotStatus = AntiBotStatus.LISTENING;
// Delay the schedule on first start
- if(startup) {
+ if (startup) {
bukkitService.scheduleSyncDelayedTask(enableTask, delay * TICKS_PER_SECOND);
startup = false;
} else {
@@ -94,19 +91,12 @@ public class AntiBotService implements SettingsDependent {
antiBotStatus = AntiBotStatus.ACTIVE;
// Inform admins
- for (Player player : bukkitService.getOnlinePlayers()) {
- if (permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) {
- messages.send(player, MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE);
- }
- }
+ bukkitService.getOnlinePlayers().stream()
+ .filter(player -> permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES))
+ .forEach(player -> messages.send(player, MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE));
// Schedule auto-disable
- disableTask = bukkitService.runTaskLater(new Runnable() {
- @Override
- public void run() {
- stopProtection();
- }
- }, duration * TICKS_PER_MINUTE);
+ disableTask = bukkitService.runTaskLater(this::stopProtection, duration * TICKS_PER_MINUTE);
}
private void stopProtection() {
@@ -116,7 +106,7 @@ public class AntiBotService implements SettingsDependent {
// Change status
antiBotStatus = AntiBotStatus.LISTENING;
- antibotPlayers = 0;
+ flagged = 0;
antibotKicked.clear();
// Cancel auto-disable task
@@ -124,11 +114,10 @@ public class AntiBotService implements SettingsDependent {
disableTask = null;
// Inform admins
- for (Player player : bukkitService.getOnlinePlayers()) {
- if (permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) {
- messages.send(player, MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE, Integer.toString(duration));
- }
- }
+ String durationString = Integer.toString(duration);
+ bukkitService.getOnlinePlayers().stream()
+ .filter(player -> permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES))
+ .forEach(player -> messages.send(player, MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE, durationString));
}
/**
@@ -155,36 +144,33 @@ public class AntiBotService implements SettingsDependent {
}
}
- /**
- * Handles a player joining the server and checks if AntiBot needs to be activated.
- */
- public void handlePlayerJoin() {
- if (antiBotStatus != AntiBotStatus.LISTENING) {
- return;
- }
-
- antibotPlayers++;
- if (antibotPlayers > sensibility) {
- startProtection();
- return;
- }
-
- bukkitService.scheduleSyncDelayedTask(new Runnable() {
- @Override
- public void run() {
- antibotPlayers--;
- }
- }, 5 * TICKS_PER_SECOND);
- }
-
/**
* Returns if a player should be kicked due to antibot service.
*
- * @param isAuthAvailable if the player is registered
* @return if the player should be kicked
*/
- public boolean shouldKick(boolean isAuthAvailable) {
- return !isAuthAvailable && (antiBotStatus == AntiBotStatus.ACTIVE);
+ public boolean shouldKick() {
+ if (antiBotStatus == AntiBotStatus.DISABLED) {
+ return false;
+ } else if (antiBotStatus == AntiBotStatus.ACTIVE) {
+ return true;
+ }
+
+ if (lastFlaggedJoin == null) {
+ lastFlaggedJoin = Instant.now();
+ }
+ if (ChronoUnit.SECONDS.between(lastFlaggedJoin, Instant.now()) <= interval) {
+ flagged++;
+ } else {
+ // reset to 1 because this player is also count as not registered
+ flagged = 1;
+ lastFlaggedJoin = null;
+ }
+ if (flagged > sensibility) {
+ startProtection();
+ return true;
+ }
+ return false;
}
/**
diff --git a/src/main/java/fr/xephi/authme/service/BackupService.java b/src/main/java/fr/xephi/authme/service/BackupService.java
index b5dfa06d3..846e34415 100644
--- a/src/main/java/fr/xephi/authme/service/BackupService.java
+++ b/src/main/java/fr/xephi/authme/service/BackupService.java
@@ -104,36 +104,22 @@ public class BackupService {
dirBackup.mkdir();
}
String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH);
- if (checkWindows(backupWindowsPath)) {
- String executeCmd = backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql";
- Process runtimeProcess;
- try {
- runtimeProcess = Runtime.getRuntime().exec(executeCmd);
- int processComplete = runtimeProcess.waitFor();
- if (processComplete == 0) {
- ConsoleLogger.info("Backup created successfully.");
- return true;
- } else {
- ConsoleLogger.warning("Could not create the backup! (Windows)");
- }
- } catch (IOException | InterruptedException e) {
- ConsoleLogger.logException("Error during Windows backup:", e);
- }
- } else {
- String executeCmd = "mysqldump -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql";
- Process runtimeProcess;
- try {
- runtimeProcess = Runtime.getRuntime().exec(executeCmd);
- int processComplete = runtimeProcess.waitFor();
- if (processComplete == 0) {
- ConsoleLogger.info("Backup created successfully.");
- return true;
- } else {
- ConsoleLogger.warning("Could not create the backup!");
- }
- } catch (IOException | InterruptedException e) {
- ConsoleLogger.logException("Error during backup:", e);
+ boolean isUsingWindows = checkWindows(backupWindowsPath);
+ String backupCommand = isUsingWindows
+ ? backupWindowsPath + "\\bin\\mysqldump.exe" + buildMysqlDumpArguments()
+ : "mysqldump" + buildMysqlDumpArguments();
+
+ try {
+ Process runtimeProcess = Runtime.getRuntime().exec(backupCommand);
+ int processComplete = runtimeProcess.waitFor();
+ if (processComplete == 0) {
+ ConsoleLogger.info("Backup created successfully. (Using Windows = " + isUsingWindows + ")");
+ return true;
+ } else {
+ ConsoleLogger.warning("Could not create the backup! (Using Windows = " + isUsingWindows + ")");
}
+ } catch (IOException | InterruptedException e) {
+ ConsoleLogger.logException("Error during backup (using Windows = " + isUsingWindows + "):", e);
}
return false;
}
@@ -173,6 +159,16 @@ public class BackupService {
return false;
}
+ /**
+ * Builds the command line arguments to pass along when running the {@code mysqldump} command.
+ *
+ * @return the mysqldump command line arguments
+ */
+ private String buildMysqlDumpArguments() {
+ return " -u " + dbUserName + " -p" + dbPassword + " " + dbName
+ + " --tables " + tblname + " -r " + path + ".sql";
+ }
+
private static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
diff --git a/src/main/java/fr/xephi/authme/service/BukkitService.java b/src/main/java/fr/xephi/authme/service/BukkitService.java
index cd5595fff..603e39757 100644
--- a/src/main/java/fr/xephi/authme/service/BukkitService.java
+++ b/src/main/java/fr/xephi/authme/service/BukkitService.java
@@ -10,6 +10,7 @@ import org.bukkit.BanList;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.plugin.Plugin;
@@ -17,6 +18,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
+import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -40,7 +42,8 @@ public class BukkitService implements SettingsDependent {
private Method getOnlinePlayers;
private boolean useAsyncTasks;
- public BukkitService(AuthMe authMe, Settings settings) {
+ @Inject
+ BukkitService(AuthMe authMe, Settings settings) {
this.authMe = authMe;
getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField();
reload(settings);
@@ -271,6 +274,27 @@ public class BukkitService implements SettingsDependent {
return Bukkit.getWorld(name);
}
+ /**
+ * Dispatches a command on this server, and executes it if found.
+ *
+ * @param sender the apparent sender of the command
+ * @param commandLine the command + arguments. Example: test abc 123
+ * @return returns false if no target is found
+ */
+ public boolean dispatchCommand(CommandSender sender, String commandLine) {
+ return Bukkit.dispatchCommand(sender, commandLine);
+ }
+
+ /**
+ * Dispatches a command to be run as console user on this server, and executes it if found.
+ *
+ * @param commandLine the command + arguments. Example: test abc 123
+ * @return returns false if no target is found
+ */
+ public boolean dispatchConsoleCommand(String commandLine) {
+ return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), commandLine);
+ }
+
@Override
public void reload(Settings settings) {
useAsyncTasks = settings.getProperty(PluginSettings.USE_ASYNC_TASKS);
@@ -307,5 +331,4 @@ public class BukkitService implements SettingsDependent {
public BanEntry banIp(String ip, String reason, Date expires, String source) {
return Bukkit.getServer().getBanList(BanList.Type.IP).addBan(ip, reason, expires, source);
}
-
}
diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/service/CommonService.java
similarity index 71%
rename from src/main/java/fr/xephi/authme/process/ProcessService.java
rename to src/main/java/fr/xephi/authme/service/CommonService.java
index 575b80536..1b1d9593b 100644
--- a/src/main/java/fr/xephi/authme/process/ProcessService.java
+++ b/src/main/java/fr/xephi/authme/service/CommonService.java
@@ -1,4 +1,4 @@
-package fr.xephi.authme.process;
+package fr.xephi.authme.service;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.message.MessageKey;
@@ -8,16 +8,15 @@ import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
-import fr.xephi.authme.service.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
- * Service for asynchronous and synchronous processes.
+ * Service for the most common operations regarding settings, messages and permissions.
*/
-public class ProcessService {
+public class CommonService {
@Inject
private Settings settings;
@@ -25,17 +24,17 @@ public class ProcessService {
@Inject
private Messages messages;
- @Inject
- private ValidationService validationService;
-
@Inject
private PermissionsManager permissionsManager;
@Inject
private AuthGroupHandler authGroupHandler;
+ CommonService() {
+ }
+
/**
- * Retrieve a property's value.
+ * Retrieves a property's value.
*
* @param property the property to retrieve
* @param the property type
@@ -46,16 +45,7 @@ public class ProcessService {
}
/**
- * Return the settings manager.
- *
- * @return settings manager
- */
- public Settings getSettings() {
- return settings;
- }
-
- /**
- * Send a message to the command sender.
+ * Sends a message to the command sender.
*
* @param sender the command sender
* @param key the message key
@@ -65,7 +55,7 @@ public class ProcessService {
}
/**
- * Send a message to the command sender with the given replacements.
+ * Sends a message to the command sender with the given replacements.
*
* @param sender the command sender
* @param key the message key
@@ -76,7 +66,7 @@ public class ProcessService {
}
/**
- * Retrieve a message.
+ * Retrieves a message.
*
* @param key the key of the message
* @return the message, split by line
@@ -86,7 +76,7 @@ public class ProcessService {
}
/**
- * Retrieve a message as one piece.
+ * Retrieves a message in one piece.
*
* @param key the key of the message
* @return the message
@@ -95,18 +85,24 @@ public class ProcessService {
return messages.retrieveSingle(key);
}
- public boolean validateEmail(String email) {
- return validationService.validateEmail(email);
- }
-
- public boolean isEmailFreeForRegistration(String email, CommandSender sender) {
- return validationService.isEmailFreeForRegistration(email, sender);
- }
-
+ /**
+ * Checks whether the player has the given permission.
+ *
+ * @param player the player
+ * @param node the permission node to check
+ * @return true if player has permission, false otherwise
+ */
public boolean hasPermission(Player player, PermissionNode node) {
return permissionsManager.hasPermission(player, node);
}
+ /**
+ * Sets the permission group of the given player.
+ *
+ * @param player the player to process
+ * @param group the group to add the player to
+ * @return true on success, false otherwise
+ */
public boolean setGroup(Player player, AuthGroupType group) {
return authGroupHandler.setGroup(player, group);
}
diff --git a/src/main/java/fr/xephi/authme/service/GeoIpService.java b/src/main/java/fr/xephi/authme/service/GeoIpService.java
index f1335c7df..22e9af2ca 100644
--- a/src/main/java/fr/xephi/authme/service/GeoIpService.java
+++ b/src/main/java/fr/xephi/authme/service/GeoIpService.java
@@ -17,6 +17,8 @@ import java.net.URLConnection;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
+import static com.maxmind.geoip.LookupService.GEOIP_MEMORY_CACHE;
+
public class GeoIpService {
private static final String LICENSE =
"[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com";
@@ -57,7 +59,7 @@ public class GeoIpService {
boolean dataIsOld = (System.currentTimeMillis() - dataFile.lastModified()) > TimeUnit.DAYS.toMillis(30);
if (!dataIsOld) {
try {
- lookupService = new LookupService(dataFile);
+ lookupService = new LookupService(dataFile, GEOIP_MEMORY_CACHE);
ConsoleLogger.info(LICENSE);
return true;
} catch (IOException e) {
diff --git a/src/main/java/fr/xephi/authme/service/MessageUpdater.java b/src/main/java/fr/xephi/authme/service/MessageUpdater.java
index 129a47b81..036ad9fda 100644
--- a/src/main/java/fr/xephi/authme/service/MessageUpdater.java
+++ b/src/main/java/fr/xephi/authme/service/MessageUpdater.java
@@ -57,7 +57,7 @@ public class MessageUpdater {
properties = buildPropertyEntriesForMessageKeys();
settingsManager = new SettingsManager(
- new YamlFileResource(userFile), (r, p) -> true, new ConfigurationData((List) properties));
+ new YamlFileResource(userFile), null, new ConfigurationData(properties));
}
/**
@@ -85,7 +85,6 @@ public class MessageUpdater {
}
}
- @SuppressWarnings("unchecked")
private void copyMissingMessages() {
for (Property property : properties) {
String message = userConfiguration.getString(property.getPath());
diff --git a/src/main/java/fr/xephi/authme/service/ValidationService.java b/src/main/java/fr/xephi/authme/service/ValidationService.java
index e3a69fc94..c6cdd99a1 100644
--- a/src/main/java/fr/xephi/authme/service/ValidationService.java
+++ b/src/main/java/fr/xephi/authme/service/ValidationService.java
@@ -40,7 +40,8 @@ public class ValidationService implements Reloadable {
private Pattern passwordRegex;
private Set unrestrictedNames;
- ValidationService() { }
+ ValidationService() {
+ }
@PostConstruct
@Override
diff --git a/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java b/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java
new file mode 100644
index 000000000..8b1fa7893
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/EnumSetProperty.java
@@ -0,0 +1,46 @@
+package fr.xephi.authme.settings;
+
+import com.github.authme.configme.SettingsManager;
+import com.github.authme.configme.properties.StringListProperty;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Property whose value is a set of entries of a given enum.
+ */
+// TODO #1014: This property type currently extends StringListProperty with a dedicated method to convert the values
+// into a Set of the selected enum due to multiple issues on ConfigMe's side.
+public class EnumSetProperty> extends StringListProperty {
+
+ private final Class enumClass;
+
+ public EnumSetProperty(Class enumClass, String path, String... values) {
+ super(path, values);
+ this.enumClass = enumClass;
+ }
+
+ /**
+ * Returns the value as a set of enum entries.
+ *
+ * @param settings the settings manager to look up the raw value with
+ * @return the property's value as mapped enum entries
+ */
+ public Set asEnumSet(SettingsManager settings) {
+ List entries = settings.getProperty(this);
+ return entries.stream()
+ .map(str -> toEnum(str))
+ .filter(e -> e != null)
+ .collect(Collectors.toSet());
+ }
+
+ private E toEnum(String str) {
+ for (E e : enumClass.getEnumConstants()) {
+ if (str.equalsIgnoreCase(e.name())) {
+ return e;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java
index fb4c06246..5bf9d0030 100644
--- a/src/main/java/fr/xephi/authme/settings/Settings.java
+++ b/src/main/java/fr/xephi/authme/settings/Settings.java
@@ -68,7 +68,7 @@ public class Settings extends SettingsManager {
private void loadSettingsFromFiles() {
passwordEmailMessage = readFile("email.html");
recoveryCodeEmailMessage = readFile("recovery_code_email.html");
- welcomeMessage = readFile("welcome.txt").split("\n");
+ welcomeMessage = readFile("welcome.txt").split("\\n");
}
@Override
diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
index 30163bf0f..529327704 100644
--- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
+++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
@@ -2,15 +2,20 @@ package fr.xephi.authme.settings;
import com.github.authme.configme.migration.PlainMigrationService;
import com.github.authme.configme.properties.Property;
+import com.github.authme.configme.properties.StringListProperty;
import com.github.authme.configme.resource.PropertyResource;
import com.google.common.base.Objects;
import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.properties.PluginSettings;
+import fr.xephi.authme.settings.properties.SecuritySettings;
+import javax.inject.Inject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
@@ -29,7 +34,17 @@ public class SettingsMigrationService extends PlainMigrationService {
private final File pluginFolder;
- public SettingsMigrationService(File pluginFolder) {
+ // Stores old commands that need to be migrated to the new commands configuration
+ // We need to store it in here for retrieval when we build the CommandConfig. Retrieving it from the config.yml is
+ // not possible since this migration service may trigger config.yml to be resaved. As the old command settings
+ // don't exist in the code anymore, as soon as config.yml is resaved we lose this information.
+ private List onLoginCommands = Collections.emptyList();
+ private List onLoginConsoleCommands = Collections.emptyList();
+ private List onRegisterCommands = Collections.emptyList();
+ private List onRegisterConsoleCommands = Collections.emptyList();
+
+ @Inject
+ SettingsMigrationService(@DataFolder File pluginFolder) {
this.pluginFolder = pluginFolder;
}
@@ -41,6 +56,8 @@ public class SettingsMigrationService extends PlainMigrationService {
changes = true;
}
+ gatherOldCommandSettings(resource);
+
// Note ljacqu 20160211: Concatenating migration methods with | instead of the usual ||
// ensures that all migrations will be performed
return changes
@@ -49,6 +66,7 @@ public class SettingsMigrationService extends PlainMigrationService {
| migrateForceSpawnSettings(resource)
| changeBooleanSettingToLogLevelProperty(resource)
| hasOldHelpHeaderProperty(resource)
+ | hasSupportOldPasswordProperty(resource)
|| hasDeprecatedProperties(resource);
}
@@ -57,7 +75,9 @@ public class SettingsMigrationService extends PlainMigrationService {
"Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications",
"Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt",
"VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite",
- "Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping"};
+ "Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping",
+ "settings.restrictions.keepCollisionsDisabled", "settings.forceCommands", "settings.forceCommandsAsConsole",
+ "settings.forceRegisterCommands", "settings.forceRegisterCommandsAsConsole"};
for (String deprecatedPath : deprecatedProperties) {
if (resource.contains(deprecatedPath)) {
return true;
@@ -66,6 +86,37 @@ public class SettingsMigrationService extends PlainMigrationService {
return false;
}
+ // ----------------
+ // Forced commands relocation (from config.yml to commands.yml)
+ // ----------------
+ private void gatherOldCommandSettings(PropertyResource resource) {
+ onLoginCommands = getStringList(resource, "settings.forceCommands");
+ onLoginConsoleCommands = getStringList(resource, "settings.forceCommandsAsConsole");
+ onRegisterCommands = getStringList(resource, "settings.forceRegisterCommands");
+ onRegisterConsoleCommands = getStringList(resource, "settings.forceRegisterCommandsAsConsole");
+ }
+
+ private List getStringList(PropertyResource resource, String path) {
+ List entries = new StringListProperty(path).getFromResource(resource);
+ return entries == null ? Collections.emptyList() : entries;
+ }
+
+ public List getOnLoginCommands() {
+ return onLoginCommands;
+ }
+
+ public List getOnLoginConsoleCommands() {
+ return onLoginConsoleCommands;
+ }
+
+ public List getOnRegisterCommands() {
+ return onRegisterCommands;
+ }
+
+ public List getOnRegisterConsoleCommands() {
+ return onRegisterConsoleCommands;
+ }
+
// --------
// Specific migrations
// --------
@@ -118,7 +169,7 @@ public class SettingsMigrationService extends PlainMigrationService {
}
/**
- * Detect old "force spawn loc on join" and "force spawn on these worlds" settings and moves them
+ * Detects old "force spawn loc on join" and "force spawn on these worlds" settings and moves them
* to the new paths.
*
* @param resource The property resource
@@ -163,6 +214,16 @@ public class SettingsMigrationService extends PlainMigrationService {
return false;
}
+ private static boolean hasSupportOldPasswordProperty(PropertyResource resource) {
+ String path = "settings.security.supportOldPasswordHash";
+ if (resource.contains(path)) {
+ ConsoleLogger.warning("Property '" + path + "' is no longer supported. "
+ + "Use '" + SecuritySettings.LEGACY_HASHES.getPath() + "' instead.");
+ return true;
+ }
+ return false;
+ }
+
/**
* Checks for an old property path and moves it to a new path if present.
*
diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
index b3a06f5eb..ac1742fa6 100644
--- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
+++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
@@ -48,10 +48,10 @@ public class SpawnLoader implements Reloadable {
@Inject
SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService,
DataSource dataSource) {
- File spawnFile = new File(pluginFolder, "spawn.yml");
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
+ File spawnFile = new File(pluginFolder, "spawn.yml");
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
- this.authMeConfigurationFile = new File(pluginFolder, "spawn.yml");
+ this.authMeConfigurationFile = spawnFile;
this.settings = settings;
this.pluginHookService = pluginHookService;
reload();
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java b/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java
new file mode 100644
index 000000000..3828dc0ee
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/Command.java
@@ -0,0 +1,50 @@
+package fr.xephi.authme.settings.commandconfig;
+
+/**
+ * Command to be run.
+ */
+public class Command {
+
+ /** The command to execute. */
+ private String command;
+ /** The executor of the command. */
+ private Executor executor = Executor.PLAYER;
+
+ /**
+ * Default constructor (for bean mapping).
+ */
+ public Command() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param command the command
+ * @param executor the executor of the command
+ */
+ public Command(String command, Executor executor) {
+ this.command = command;
+ this.executor = executor;
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+ public void setCommand(String command) {
+ this.command = command;
+ }
+
+ public Executor getExecutor() {
+ return executor;
+ }
+
+ public void setExecutor(Executor executor) {
+ this.executor = executor;
+ }
+
+ @Override
+ public String toString() {
+ return command + " (" + executor + ")";
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java
new file mode 100644
index 000000000..19c05505f
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java
@@ -0,0 +1,40 @@
+package fr.xephi.authme.settings.commandconfig;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Command configuration.
+ *
+ * @see CommandManager
+ */
+public class CommandConfig {
+
+ private Map onJoin = new LinkedHashMap<>();
+ private Map onLogin = new LinkedHashMap<>();
+ private Map onRegister = new LinkedHashMap<>();
+
+ public Map getOnJoin() {
+ return onJoin;
+ }
+
+ public void setOnJoin(Map onJoin) {
+ this.onJoin = onJoin;
+ }
+
+ public Map getOnLogin() {
+ return onLogin;
+ }
+
+ public void setOnLogin(Map onLogin) {
+ this.onLogin = onLogin;
+ }
+
+ public Map getOnRegister() {
+ return onRegister;
+ }
+
+ public void setOnRegister(Map onRegister) {
+ this.onRegister = onRegister;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java
new file mode 100644
index 000000000..f21f7e5cb
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java
@@ -0,0 +1,84 @@
+package fr.xephi.authme.settings.commandconfig;
+
+import com.github.authme.configme.SettingsManager;
+import com.github.authme.configme.resource.YamlFileResource;
+import fr.xephi.authme.initialization.DataFolder;
+import fr.xephi.authme.initialization.Reloadable;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.util.FileUtils;
+import org.bukkit.entity.Player;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.util.Map;
+
+/**
+ * Manages configurable commands to be run when various events occur.
+ */
+public class CommandManager implements Reloadable {
+
+ private final File dataFolder;
+ private final BukkitService bukkitService;
+ private final CommandMigrationService commandMigrationService;
+
+ private CommandConfig commandConfig;
+
+ @Inject
+ CommandManager(@DataFolder File dataFolder, BukkitService bukkitService,
+ CommandMigrationService commandMigrationService) {
+ this.dataFolder = dataFolder;
+ this.bukkitService = bukkitService;
+ this.commandMigrationService = commandMigrationService;
+ reload();
+ }
+
+ /**
+ * Runs the configured commands for when a player has joined.
+ *
+ * @param player the joining player
+ */
+ public void runCommandsOnJoin(Player player) {
+ executeCommands(player, commandConfig.getOnJoin());
+ }
+
+ /**
+ * Runs the configured commands for when a player has successfully registered.
+ *
+ * @param player the player who has registered
+ */
+ public void runCommandsOnRegister(Player player) {
+ executeCommands(player, commandConfig.getOnRegister());
+ }
+
+ /**
+ * Runs the configured commands for when a player has logged in successfully.
+ *
+ * @param player the player that logged in
+ */
+ public void runCommandsOnLogin(Player player) {
+ executeCommands(player, commandConfig.getOnLogin());
+ }
+
+ private void executeCommands(Player player, Map commands) {
+ for (Command command : commands.values()) {
+ final String execution = command.getCommand().replace("%p", player.getName());
+ if (Executor.CONSOLE.equals(command.getExecutor())) {
+ bukkitService.dispatchConsoleCommand(execution);
+ } else {
+ bukkitService.dispatchCommand(player, execution);
+ }
+ }
+ }
+
+ @Override
+ public void reload() {
+ File file = new File(dataFolder, "commands.yml");
+ FileUtils.copyFileFromResource(file, "commands.yml");
+
+ SettingsManager settingsManager = new SettingsManager(
+ new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
+ commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
+ }
+
+
+}
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java
new file mode 100644
index 000000000..6b357615f
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java
@@ -0,0 +1,122 @@
+package fr.xephi.authme.settings.commandconfig;
+
+import com.github.authme.configme.migration.MigrationService;
+import com.github.authme.configme.properties.Property;
+import com.github.authme.configme.resource.PropertyResource;
+import com.google.common.annotations.VisibleForTesting;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.settings.SettingsMigrationService;
+import fr.xephi.authme.util.RandomStringUtils;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Migrates the commands from their old location, in config.yml, to the dedicated commands configuration file.
+ */
+class CommandMigrationService implements MigrationService {
+
+ @Inject
+ private SettingsMigrationService settingsMigrationService;
+
+ CommandMigrationService() {
+ }
+
+ @Override
+ public boolean checkAndMigrate(PropertyResource resource, List> properties) {
+ final CommandConfig commandConfig = CommandSettingsHolder.COMMANDS.getValue(resource);
+ final boolean didMoveCommands = transformOldCommands(commandConfig);
+
+ if (didMoveCommands) { // TODO ConfigMe/#29: Check that loaded file isn't completely empty
+ resource.setValue("", commandConfig);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Adds command settings from their old location (in config.yml) to the given command configuration object.
+ *
+ * @param commandConfig the command config object to move old commands to
+ * @return true if commands have been moved, false if no migration was necessary
+ */
+ @VisibleForTesting
+ boolean transformOldCommands(CommandConfig commandConfig) {
+ boolean didMoveCommands = false;
+ for (MigratableCommandSection section : MigratableCommandSection.values()) {
+ didMoveCommands |= section.convertCommands(settingsMigrationService, commandConfig);
+ }
+ return didMoveCommands;
+ }
+
+ /**
+ * Enum defining the forced command settings that should be moved from config.yml to the new commands.yml file.
+ */
+ private enum MigratableCommandSection {
+
+ ON_JOIN(
+ SettingsMigrationService::getOnLoginCommands,
+ Executor.PLAYER,
+ CommandConfig::getOnLogin),
+
+ ON_JOIN_CONSOLE(
+ SettingsMigrationService::getOnLoginConsoleCommands,
+ Executor.CONSOLE,
+ CommandConfig::getOnLogin),
+
+ ON_REGISTER(
+ SettingsMigrationService::getOnRegisterCommands,
+ Executor.PLAYER,
+ CommandConfig::getOnRegister),
+
+ ON_REGISTER_CONSOLE(
+ SettingsMigrationService::getOnRegisterConsoleCommands,
+ Executor.CONSOLE,
+ CommandConfig::getOnRegister);
+
+ private final Function> legacyCommandsGetter;
+ private final Executor executor;
+ private final Function> commandMapGetter;
+
+ /**
+ * Constructor.
+ *
+ * @param legacyCommandsGetter getter on MigrationService to get the deprecated command entries
+ * @param executor the executor of the commands
+ * @param commandMapGetter the getter for the commands map in the new settings structure to add the old
+ * settings to after conversion
+ */
+ MigratableCommandSection(Function> legacyCommandsGetter,
+ Executor executor,
+ Function> commandMapGetter) {
+ this.legacyCommandsGetter = legacyCommandsGetter;
+ this.executor = executor;
+ this.commandMapGetter = commandMapGetter;
+ }
+
+ /**
+ * Adds the commands from the sections' settings migration service to the appropriate place in the new
+ * command config object.
+ *
+ * @param settingsMigrationService settings migration service to read old commands from
+ * @param commandConfig command config object to add converted commands to
+ * @return true if there were commands to migrate, false otherwise
+ */
+ boolean convertCommands(SettingsMigrationService settingsMigrationService, CommandConfig commandConfig) {
+ List commands = legacyCommandsGetter.apply(settingsMigrationService).stream()
+ .map(cmd -> new Command(cmd, executor)).collect(Collectors.toList());
+
+ if (commands.isEmpty()) {
+ return false;
+ }
+ Map commandMap = commandMapGetter.apply(commandConfig);
+ commands.forEach(cmd -> commandMap.put(RandomStringUtils.generate(10), cmd));
+ ConsoleLogger.info("Moving " + commands.size() + " commands of type " + this
+ + " from config.yml to commands.yml");
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java
new file mode 100644
index 000000000..99a1c6e8c
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java
@@ -0,0 +1,54 @@
+package fr.xephi.authme.settings.commandconfig;
+
+import com.github.authme.configme.SectionComments;
+import com.github.authme.configme.SettingsHolder;
+import com.github.authme.configme.beanmapper.BeanProperty;
+import com.github.authme.configme.properties.Property;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Settings holder class for the commands.yml settings.
+ */
+public final class CommandSettingsHolder implements SettingsHolder {
+
+ public static final Property COMMANDS =
+ new BeanProperty<>(CommandConfig.class, "", new CommandConfig());
+
+
+ private CommandSettingsHolder() {
+ }
+
+ @SectionComments
+ public static Map sectionComments() {
+ String[] comments = {
+ "This configuration file allows you to execute commands on various events.",
+ "%p in commands will be replaced with the player name.",
+ "For example, if you want to send a welcome message to a player who just registered:",
+ "onRegister:",
+ " welcome:",
+ " command: 'msg %p Welcome to the server!'",
+ " as: CONSOLE",
+ "",
+ "This will make the console execute the msg command to the player.",
+ "Each command under an event has a name you can choose freely (e.g. 'welcome' as above),",
+ "after which a mandatory 'command' field defines the command to run,",
+ "and 'as' defines who will run the command (either PLAYER or CONSOLE). Longer example:",
+ "onLogin:",
+ " welcome:",
+ " command: 'msg %p Welcome back!'",
+ " as: PLAYER",
+ " broadcast:",
+ " command: 'broadcast %p has joined, welcome back!'",
+ " as: CONSOLE",
+ "",
+ "Supported command events: onLogin, onJoin, onRegister"
+ };
+ Map commentMap = new HashMap<>();
+ // TODO ConfigMe/#25 cannot set comments on the root ("")
+ commentMap.put("onLogin", comments);
+ return commentMap;
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java b/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java
new file mode 100644
index 000000000..c7043de2d
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/settings/commandconfig/Executor.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.settings.commandconfig;
+
+/**
+ * The executor of the command.
+ */
+public enum Executor {
+
+ /** The player of the event. */
+ PLAYER,
+
+ /** The console user. */
+ CONSOLE
+
+}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java b/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java
index 80bd02cfd..88b896f6f 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/AuthMeSettingsRetriever.java
@@ -6,8 +6,7 @@ import com.github.authme.configme.knownproperties.ConfigurationDataBuilder;
import com.github.authme.configme.properties.Property;
/**
- * Utility class responsible for retrieving all {@link Property} fields
- * from {@link SettingsHolder} implementations via reflection.
+ * Utility class responsible for retrieving all {@link Property} fields from {@link SettingsHolder} classes.
*/
public final class AuthMeSettingsRetriever {
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 77b1767ed..68d2ad73d 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java
@@ -25,7 +25,7 @@ public class HooksSettings implements SettingsHolder {
@Comment("Do we need to disable Essentials SocialSpy on join?")
public static final Property DISABLE_SOCIAL_SPY =
- newProperty("Hooks.disableSocialSpy", true);
+ newProperty("Hooks.disableSocialSpy", false);
@Comment("Do we need to force /motd Essentials command on join?")
public static final Property USE_ESSENTIALS_MOTD =
diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
index bfb565337..91d71d7ff 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
@@ -36,7 +36,10 @@ public class PluginSettings implements SettingsHolder {
public static final Property SESSIONS_EXPIRE_ON_IP_CHANGE =
newProperty("settings.sessions.sessionExpireOnIpChange", true);
- @Comment("Message language, available: en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt")
+ @Comment({
+ "Message language, available languages:",
+ "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md"
+ })
public static final Property MESSAGES_LANGUAGE =
newProperty("settings.messagesLanguage", "en");
@@ -49,13 +52,6 @@ public class PluginSettings implements SettingsHolder {
public static final Property ENABLE_PERMISSION_CHECK =
newProperty("permission.EnablePermissionCheck", false);
- @Comment({
- "Keeps collisions disabled for logged players",
- "Works only with MC 1.9"
- })
- public static final Property KEEP_COLLISIONS_DISABLED =
- newProperty("settings.restrictions.keepCollisionsDisabled", false);
-
@Comment({
"Log level: INFO, FINE, DEBUG. Use INFO for general messages,",
"FINE for some additional detailed ones (like password failed),",
@@ -65,8 +61,8 @@ public class PluginSettings implements SettingsHolder {
newProperty(LogLevel.class, "settings.logLevel", LogLevel.FINE);
@Comment({
- "By default we schedule async tasks when talking to the database",
- "If you want typical communication with the database to happen synchronously, set this to false"
+ "By default we schedule async tasks when talking to the database. If you want",
+ "typical communication with the database to happen synchronously, set this to false"
})
public static final Property USE_ASYNC_TASKS =
newProperty("settings.useAsyncTasks", true);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
index cdd760bd2..b725172f0 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
@@ -20,13 +20,16 @@ public class ProtectionSettings implements SettingsHolder {
public static final Property ENABLE_PROTECTION_REGISTERED =
newProperty("Protection.enableProtectionRegistered", true);
- @Comment({"Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes",
- "PLEASE USE QUOTES!"})
+ @Comment({
+ "Countries allowed to join the server and register. For country codes, see",
+ "http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/",
+ "PLEASE USE QUOTES!"})
public static final Property> COUNTRIES_WHITELIST =
newListProperty("Protection.countries", "US", "GB");
- @Comment({"Countries not allowed to join the server and register",
- "PLEASE USE QUOTES!"})
+ @Comment({
+ "Countries not allowed to join the server and register",
+ "PLEASE USE QUOTES!"})
public static final Property> COUNTRIES_BLACKLIST =
newListProperty("Protection.countriesBlacklist", "A1");
@@ -34,7 +37,13 @@ public class ProtectionSettings implements SettingsHolder {
public static final Property ENABLE_ANTIBOT =
newProperty("Protection.enableAntiBot", true);
- @Comment("Max number of players allowed to login in 5 secs before the AntiBot system is enabled automatically")
+ @Comment("The interval in seconds")
+ public static final Property ANTIBOT_INTERVAL =
+ newProperty("Protection.antiBotInterval", 5);
+
+ @Comment({
+ "Max number of players allowed to login in the interval",
+ "before the AntiBot system is enabled automatically"})
public static final Property ANTIBOT_SENSIBILITY =
newProperty("Protection.antiBotSensibility", 10);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
index f23a3eb12..b3733b5ac 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
@@ -12,7 +12,7 @@ public class PurgeSettings implements SettingsHolder {
public static final Property USE_AUTO_PURGE =
newProperty("Purge.useAutoPurge", false);
- @Comment("Number of Days an account become Unused")
+ @Comment("Number of days after which an account should be purged")
public static final Property DAYS_BEFORE_REMOVE_PLAYER =
newProperty("Purge.daysBeforeRemovePlayer", 60);
@@ -28,7 +28,7 @@ public class PurgeSettings implements SettingsHolder {
public static final Property DEFAULT_WORLD =
newProperty("Purge.defaultWorld", "world");
- @Comment("Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ?")
+ @Comment("Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?")
public static final Property REMOVE_LIMITED_CREATIVE_INVENTORIES =
newProperty("Purge.removeLimitedCreativesInventories", false);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
index b593869a3..a3de56b82 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
@@ -4,9 +4,6 @@ import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
-import java.util.List;
-
-import static com.github.authme.configme.properties.PropertyInitializer.newListProperty;
import static com.github.authme.configme.properties.PropertyInitializer.newProperty;
public class RegistrationSettings implements SettingsHolder {
@@ -48,35 +45,19 @@ public class RegistrationSettings implements SettingsHolder {
public static final Property FORCE_LOGIN_AFTER_REGISTER =
newProperty("settings.registration.forceLoginAfterRegister", false);
- @Comment("Force these commands after /login, without any '/', use %p to replace with player name")
- public static final Property> FORCE_COMMANDS =
- newListProperty("settings.forceCommands");
-
- @Comment("Force these commands after /login as service console, without any '/'. "
- + "Use %p to replace with player name")
- public static final Property> FORCE_COMMANDS_AS_CONSOLE =
- newListProperty("settings.forceCommandsAsConsole");
-
- @Comment("Force these commands after /register, without any '/', use %p to replace with player name")
- public static final Property> FORCE_REGISTER_COMMANDS =
- newListProperty("settings.forceRegisterCommands");
-
- @Comment("Force these commands after /register as a server console, without any '/'. "
- + "Use %p to replace with player name")
- public static final Property> FORCE_REGISTER_COMMANDS_AS_CONSOLE =
- newListProperty("settings.forceRegisterCommandsAsConsole");
-
@Comment({
"Enable to display the welcome message (welcome.txt) after a login",
"You can use colors in this welcome.txt + some replaced strings:",
- "{PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots,",
- "{IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name",
+ "{PLAYER}: player name, {ONLINE}: display number of online players,",
+ "{MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged,",
+ "{WORLD}: player current world, {SERVER}: server name",
"{VERSION}: get current bukkit version, {COUNTRY}: player country"})
public static final Property USE_WELCOME_MESSAGE =
newProperty("settings.useWelcomeMessage", true);
- @Comment("Do we need to broadcast the welcome message to all server or only to the player? set true for "
- + "server or false for player")
+ @Comment({
+ "Broadcast the welcome message to the server or only to the player?",
+ "set true for server or false for player"})
public static final Property BROADCAST_WELCOME_MESSAGE =
newProperty("settings.broadcastWelcomeMessage", false);
@@ -104,7 +85,7 @@ public class RegistrationSettings implements SettingsHolder {
"Do we need to prevent people to login with another case?",
"If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI"})
public static final Property PREVENT_OTHER_CASE =
- newProperty("settings.preventOtherCase", false);
+ newProperty("settings.preventOtherCase", true);
private RegistrationSettings() {
diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
index 9e16714dd..c62b93e3b 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
@@ -36,7 +36,7 @@ public class RestrictionSettings implements SettingsHolder {
@Comment("Minimum allowed username length")
public static final Property MIN_NICKNAME_LENGTH =
- newProperty("settings.restrictions.minNicknameLength", 4);
+ newProperty("settings.restrictions.minNicknameLength", 3);
@Comment("Maximum allowed username length")
public static final Property MAX_NICKNAME_LENGTH =
@@ -50,9 +50,9 @@ public class RestrictionSettings implements SettingsHolder {
newProperty("settings.restrictions.ForceSingleSession", true);
@Comment({
- "If enabled, every player that spawn in one of the world listed in \"ForceSpawnLocOnJoin.worlds\"",
- "will be teleported to the spawnpoint after successful authentication.",
- "The quit location of the player will be overwritten.",
+ "If enabled, every player that spawn in one of the world listed in",
+ "\"ForceSpawnLocOnJoin.worlds\" will be teleported to the spawnpoint after successful",
+ "authentication. The quit location of the player will be overwritten.",
"This is different from \"teleportUnAuthedToSpawn\" that teleport player",
"to the spawnpoint on join."})
public static final Property FORCE_SPAWN_LOCATION_AFTER_LOGIN =
@@ -77,7 +77,7 @@ public class RestrictionSettings implements SettingsHolder {
@Comment({
"The restricted user feature will kick players listed below",
- "if they don't match the defined IP address.",
+ "if they don't match the defined IP address. Names are case-insensitive.",
"Example:",
" AllowedRestrictedUser:",
" - playername;127.0.0.1"})
@@ -90,7 +90,7 @@ public class RestrictionSettings implements SettingsHolder {
@Comment("Should players be kicked on wrong password?")
public static final Property KICK_ON_WRONG_PASSWORD =
- newProperty("settings.restrictions.kickOnWrongPassword", false);
+ newProperty("settings.restrictions.kickOnWrongPassword", true);
@Comment({
"Should not logged in players be teleported to the spawn?",
@@ -139,7 +139,7 @@ public class RestrictionSettings implements SettingsHolder {
@Comment("Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.")
public static final Property DENY_TABCOMPLETE_BEFORE_LOGIN =
- newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", true);
+ newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", false);
@Comment({
"Should we display all other accounts from a player when he joins?",
@@ -176,17 +176,28 @@ public class RestrictionSettings implements SettingsHolder {
newProperty("settings.GameMode.ForceSurvivalMode", false);
@Comment({
- "Below you can list all account names that",
- "AuthMe will ignore for registration or login, configure it",
- "at your own risk!! Remember that if you are going to add",
- "nickname with [], you have to delimit name with ' '.",
- "this option add compatibility with BuildCraft and some",
- "other mods.",
- "It is case-sensitive!"
+ "Below you can list all account names that AuthMe will ignore",
+ "for registration or login. Configure it at your own risk!!",
+ "This option adds compatibility with BuildCraft and some other mods.",
+ "It is case-insensitive! Example:",
+ "UnrestrictedName:",
+ "- 'npcPlayer'",
+ "- 'npcPlayer2'"
})
public static final Property> UNRESTRICTED_NAMES =
newLowercaseListProperty("settings.unrestrictions.UnrestrictedName");
+ @Comment("Threshold of the other accounts command, a value less than 2 means disabled.")
+ public static final Property OTHER_ACCOUNTS_CMD_THRESHOLD =
+ newProperty("settings.restrictions.otherAccountsCmdThreshold", 0);
+
+ @Comment({
+ "Command to run when a user has more accounts than the configured threshold.",
+ "Available variables: %playername%, %playerip%"
+ })
+ public static final Property OTHER_ACCOUNTS_CMD =
+ newProperty("settings.restrictions.otherAccountsCmd",
+ "say The player %playername% with ip %playerip% has multiple accounts!");
private RestrictionSettings() {
}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
index 7d91f8183..5bad44b07 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
@@ -4,6 +4,7 @@ import com.github.authme.configme.Comment;
import com.github.authme.configme.SettingsHolder;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.security.HashAlgorithm;
+import fr.xephi.authme.settings.EnumSetProperty;
import java.util.List;
@@ -18,10 +19,6 @@ public class SecuritySettings implements SettingsHolder {
public static final Property STOP_SERVER_ON_PROBLEM =
newProperty("Security.SQLProblem.stopServer", true);
- @Comment("/reload support")
- public static final Property USE_RELOAD_COMMAND_SUPPORT =
- newProperty("Security.ReloadCommand.useReloadCommandSupport", true);
-
@Comment("Remove passwords from console?")
public static final Property REMOVE_PASSWORD_FROM_CONSOLE =
newProperty("Security.console.removePassword", true);
@@ -67,9 +64,10 @@ public class SecuritySettings implements SettingsHolder {
newProperty("settings.security.unLoggedinGroup", "unLoggedinGroup");
@Comment({
- "Possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,",
- "MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,",
- "DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only)"
+ "Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,",
+ "MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,",
+ "PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only). See full list at",
+ "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/hash_algorithms.md"
})
public static final Property PASSWORD_HASH =
newProperty(HashAlgorithm.class, "settings.security.passwordHash", HashAlgorithm.SHA256);
@@ -78,18 +76,28 @@ public class SecuritySettings implements SettingsHolder {
public static final Property DOUBLE_MD5_SALT_LENGTH =
newProperty("settings.security.doubleMD5SaltLength", 8);
- @Comment({"If password checking return false, do we need to check with all",
- "other password algorithm to check an old password?",
- "AuthMe will update the password to the new password hash"})
- public static final Property SUPPORT_OLD_PASSWORD_HASH =
- newProperty("settings.security.supportOldPasswordHash", false);
+ @Comment({
+ "If a password check fails, AuthMe will also try to check with the following hash methods.",
+ "Use this setting when you change from one hash method to another.",
+ "AuthMe will update the password to the new hash. Example:",
+ "legacyHashes:",
+ "- 'SHA1'"
+ })
+ public static final Property> LEGACY_HASHES =
+ new EnumSetProperty<>(HashAlgorithm.class, "settings.security.legacyHashes");
+
+ @Comment("Number of rounds to use if passwordHash is set to PBKDF2. Default is 10000")
+ public static final Property PBKDF2_NUMBER_OF_ROUNDS =
+ newProperty("settings.security.pbkdf2Rounds", 10000);
@Comment({"Prevent unsafe passwords from being used; put them in lowercase!",
+ "You should always set 'help' as unsafePassword due to possible conflicts.",
"unsafePasswords:",
"- '123456'",
- "- 'password'"})
+ "- 'password'",
+ "- 'help'"})
public static final Property> UNSAFE_PASSWORDS =
- newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789");
+ newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789", "help");
@Comment("Tempban a user's IP address if they enter the wrong password too many times")
public static final Property TEMPBAN_ON_MAX_LOGINS =
diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java b/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java
index a69c5fee5..92391af90 100644
--- a/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java
+++ b/src/main/java/fr/xephi/authme/task/purge/PurgeTask.java
@@ -72,7 +72,7 @@ class PurgeTask extends BukkitRunnable {
}
OfflinePlayer offlinePlayer = offlinePlayers[nextPosition];
- if (toPurge.remove(offlinePlayer.getName().toLowerCase())) {
+ if (offlinePlayer.getName() != null && toPurge.remove(offlinePlayer.getName().toLowerCase())) {
if (!permissionsManager.hasPermissionOffline(offlinePlayer, PlayerStatePermission.BYPASS_PURGE)) {
playerPortion.add(offlinePlayer);
namePortion.add(offlinePlayer.getName());
@@ -81,7 +81,7 @@ class PurgeTask extends BukkitRunnable {
}
if (!toPurge.isEmpty() && playerPortion.isEmpty()) {
- ConsoleLogger.info("Finished lookup up offlinePlayers. Begin looking purging player names only");
+ ConsoleLogger.info("Finished lookup of offlinePlayers. Begin looking purging player names only");
//we went through all offlineplayers but there are still names remaining
for (String name : toPurge) {
diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java
index 86c8cae46..c9edcf735 100644
--- a/src/main/java/fr/xephi/authme/util/FileUtils.java
+++ b/src/main/java/fr/xephi/authme/util/FileUtils.java
@@ -98,6 +98,22 @@ public final class FileUtils {
}
}
+ /**
+ * Creates the given file or throws an exception.
+ *
+ * @param file the file to create
+ */
+ public static void create(File file) {
+ try {
+ boolean result = file.createNewFile();
+ if (!result) {
+ throw new IllegalStateException("Could not create file '" + file + "'");
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Error while creating file '" + file + "'", e);
+ }
+ }
+
/**
* Construct a file path from the given elements, i.e. separate the given elements by the file separator.
*
diff --git a/src/main/java/fr/xephi/authme/util/RuntimeUtils.java b/src/main/java/fr/xephi/authme/util/RuntimeUtils.java
deleted file mode 100644
index 6af0c4576..000000000
--- a/src/main/java/fr/xephi/authme/util/RuntimeUtils.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package fr.xephi.authme.util;
-
-/**
- * Runtime utilities.
- */
-public class RuntimeUtils {
-
- // Utility class
- private RuntimeUtils() {
- }
-
- /**
- * Return the available core count of the JVM.
- *
- * @return the core count
- */
- public static int getCoreCount() {
- return Runtime.getRuntime().availableProcessors();
- }
-}
diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java
index 1136854d9..39419689e 100644
--- a/src/main/java/fr/xephi/authme/util/Utils.java
+++ b/src/main/java/fr/xephi/authme/util/Utils.java
@@ -48,4 +48,13 @@ public final class Utils {
return false;
}
}
+
+ /**
+ * Return the available core count of the JVM.
+ *
+ * @return the core count
+ */
+ public static int getCoreCount() {
+ return Runtime.getRuntime().availableProcessors();
+ }
}
diff --git a/src/main/resources/commands.yml b/src/main/resources/commands.yml
new file mode 100644
index 000000000..c3741a293
--- /dev/null
+++ b/src/main/resources/commands.yml
@@ -0,0 +1,26 @@
+
+# This configuration file allows you to execute commands on various events.
+# %p in commands will be replaced with the player name.
+# For example, if you want to send a welcome message to a player who just registered:
+# onRegister:
+# welcome:
+# command: 'msg %p Welcome to the server!'
+# as: CONSOLE
+#
+# This will make the console execute the msg command to the player.
+# Each command under an event has a name you can choose freely (e.g. 'welcome' as above),
+# after which a mandatory 'command' field defines the command to run,
+# and 'as' defines who will run the command (either PLAYER or CONSOLE). Longer example:
+# onLogin:
+# welcome:
+# command: 'msg %p Welcome back!'
+# as: PLAYER
+# broadcast:
+# command: 'broadcast %p has joined, welcome back!'
+# as: CONSOLE
+#
+# Supported command events: onLogin, onJoin, onRegister
+onLogin:
+ welcome:
+ command: 'msg %p Welcome back!'
+ executor: 'PLAYER'
diff --git a/src/main/resources/messages/help_br.yml b/src/main/resources/messages/help_br.yml
new file mode 100644
index 000000000..90fc6cc04
--- /dev/null
+++ b/src/main/resources/messages/help_br.yml
@@ -0,0 +1,44 @@
+# 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:
+ optional: 'Opcional'
+ hasPermission: 'Você tem permissão'
+ noPermission: 'Sem Permissão'
+ default: 'Default'
+ result: 'Resultado'
+ defaultPermissions:
+ notAllowed: 'Sem Permissão'
+ opOnly: 'OP''s only'
+ allowed: 'Todos podem'
+
+# -------------------------------------------------------
+# 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: 'Pequena 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: 'Registra um jogador'
+ detailedDescription: 'Registra um esprecifico jogador com uma senha especifica.'
+ arg1:
+ label: 'player'
+ description: 'Nome do player'
+ arg2:
+ label: 'password'
+ description: 'Senha'
diff --git a/src/main/resources/messages/help_pl.yml b/src/main/resources/messages/help_pl.yml
new file mode 100644
index 000000000..a5f59a2ea
--- /dev/null
+++ b/src/main/resources/messages/help_pl.yml
@@ -0,0 +1,45 @@
+# Tlumaczenie configu dla AuthMe pomoc, kiedy wpiszesz /authme help lub /authme help register podana wiadomosc zostanie wyslana
+
+# -------------------------------------------------------
+# Lista tekstu uzyta w pomocy.
+common:
+ header: '==========[ AuthMeReloaded - Pomoc ]=========='
+ optional: 'Opcjonalnie'
+ hasPermission: 'Nie posidasz permisji'
+ noPermission: 'Brak permisji'
+ default: 'Domyslnie'
+ result: 'Wynik'
+ defaultPermissions:
+ notAllowed: 'Nie posiadasz permisji'
+ opOnly: 'Tylko OP'
+ allowed: 'Dozwolone dla wszyskich'
+
+# -------------------------------------------------------
+# Tytuly z inwidualnych stref w pomoc.
+# Zostaw tlumaczenie puste aby wylaczyc dana komende. Np.:
+# alternatives: ''
+section:
+ command: 'Komenda'
+ description: 'Krotki opis'
+ detailedDescription: 'Dlugi opis'
+ arguments: 'Argumenty'
+ permissions: 'Permisje'
+ alternatives: 'Alternatywy'
+ children: 'Komendy'
+
+# -------------------------------------------------------
+# Mozesz przetlumaczyc wszystkie komendy uzywajac tego wzoru.
+# Na przyklad jesli chcesz przetlumaczyc /authme reload, utworz selekcje "authme.reload", lub "login" dla /login
+# Jesli komenda posiada argumenty, mozesz uzyc arg1 aby przetlumaczyc pierwszy argument, i nastepne
+# Tlumaczenia nie musza byc kompletne; kazde braki beda uzupelniane domyslnymi wiadomosciami z pluginu.
+# Uwaga: Postaw glowna klase (np. "authme") przed ich dziecmi (np. "authme.reload")
+commands:
+ authme.register:
+ description: 'Rejestracja gracza'
+ detailedDescription: 'Rerejestracja gracza z okreslonym haslem'
+ arg1:
+ label: 'player'
+ description: 'Nazwa gracza'
+ arg2:
+ label: 'password'
+ description: 'Haslo'
diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml
index 8002a7a1a..8181658cd 100644
--- a/src/main/resources/messages/messages_br.yml
+++ b/src/main/resources/messages/messages_br.yml
@@ -61,6 +61,8 @@ email_confirm: '&cPor favor confirme seu endereço de email!'
email_changed: '&2Troca de email com sucesso.!'
email_send: '&2Recuperação de email enviada com sucesso! Por favor, verifique sua caixa de entrada de e-mail!'
email_exists: '&cUm e-mail de recuperação já foi enviado! Você pode descartá-lo e enviar um novo usando o comando abaixo:'
+email_show: '&2O seu endereço de e-mail atual é: &f%email'
+show_no_email: '&2Você atualmente não têm endereço de e-mail associado a esta conta.'
country_banned: '&4O seu país está banido neste servidor!'
antibot_auto_enabled: '&4[AntiBotService] habilitado devido ao enorme número de conexões!'
antibot_auto_disabled: '&2[AntiBotService] AntiBot desativada após %m minutos!'
@@ -75,5 +77,3 @@ kicked_admin_registered: 'Um administrador registrou você; por favor faça logi
incomplete_email_settings: 'Erro: Nem todas as configurações necessárias estão definidas para o envio de e-mails. Entre em contato com um administrador.'
recovery_code_sent: 'Um código de recuperação para redefinir sua senha foi enviada para o seu e-mail.'
recovery_code_incorrect: 'O código de recuperação esta incorreto! Use /email recovery [email] para gerar um novo!'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml
index 0463d17ca..d04e38cd1 100644
--- a/src/main/resources/messages/messages_en.yml
+++ b/src/main/resources/messages/messages_en.yml
@@ -72,5 +72,6 @@ accounts_owned_self: 'You own %count accounts:'
accounts_owned_other: 'The player %name has %count accounts:'
kicked_admin_registered: 'An admin just registered you; please log in again'
incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.'
+email_send_failure: 'The email could not be sent. Please contact an administrator.'
recovery_code_sent: 'A recovery code to reset your password has been sent to your email.'
recovery_code_incorrect: 'The recovery code is not correct! Use /email recovery [email] to generate a new one'
diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml
index 8e0014789..d72c7d44b 100644
--- a/src/main/resources/messages/messages_es.yml
+++ b/src/main/resources/messages/messages_es.yml
@@ -71,8 +71,8 @@ kick_antibot: '¡El modo de protección AntiBot está habilitado! Tienes que esp
email_exists: '&c¡El correo de recuperación ya ha sido enviado! Puedes descartarlo y enviar uno nuevo utilizando el siguiente comando:'
password_error_nick: '&cNo puedes utilizar tu nombre como contraseña, por favor elige otra...'
accounts_owned_other: 'El jugador %name tiene %count cuentas:'
-incomplete_email_settings: 'Error: no todos los ajustes necesario se han configurado para enviar correos. Por favor, contacta con un administrador.'
+incomplete_email_settings: 'Error: no todos los ajustes necesarios se han configurado para enviar correos. Por favor, contacta con un administrador.'
recovery_code_sent: 'El código de recuperación para recuperar tu contraseña se ha enviado a tu correo.'
invalid_name_case: 'Solo puedes unirte mediante el nombre de usuario %valid, no %invalid.'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
+email_show: '&2Tu dirección de E-Mail actual es: &f%email'
+show_no_email: '&2No tienes ningun E-Mail asociado en esta cuenta.'
diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml
index 88142bbce..daabe5734 100644
--- a/src/main/resources/messages/messages_hu.yml
+++ b/src/main/resources/messages/messages_hu.yml
@@ -72,5 +72,5 @@ kicked_admin_registered: 'Adminisztrátor által regisztrálva lettél; kérlek
accounts_owned_self: '%count db regisztrációd van:'
recovery_code_incorrect: 'A visszaállító kód helytelen volt! Használd a következő parancsot: /email recovery [email címed] egy új generálásához'
recovery_code_sent: 'A jelszavad visszaállításához szükséges kódot sikeresen kiküldtük az email címedre!'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
+email_show: '&2A jelenlegi email-ed a következő: &f%email'
+show_no_email: '&2Ehhez a felhasználóhoz jelenleg még nincs email hozzárendelve.'
diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml
index 777ced5ff..cd3c55ac0 100644
--- a/src/main/resources/messages/messages_pl.yml
+++ b/src/main/resources/messages/messages_pl.yml
@@ -69,9 +69,9 @@ antibot_auto_enabled: '&4[AntiBotService] AntyBot wlaczony z powodu duzej liczby
accounts_owned_self: 'Posiadasz %count kont:'
two_factor_create: '&2Twoj sekretny kod to %code. Mozesz zeskanowac go tutaj %url'
not_owner_error: 'Nie jestes wlascicielem tego konta, wybierz inny nick!'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
-# TODO kicked_admin_registered: 'An admin just registered you; please log in again'
-# TODO incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.'
-# 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'
\ No newline at end of file
+email_show: '&2Twoj aktualny adres email to: &f%email'
+show_no_email: '&2Nie posiadasz adresu email przypisanego do tego konta.'
+kicked_admin_registered: 'Administrator zarejestrowal Ciebie, mozesz sie zalogowac.'
+incomplete_email_settings: 'Error: Nie wszystkie opcje odpowiedzialne za wysylanie emaili zostaly ustawione. Skontaktuj sie z administracja.'
+recovery_code_sent: 'Kod odzyskiwania hasla zostal wyslany na adres email przypisany do konta.'
+recovery_code_incorrect: 'Kod odzyskiwania hasla jest bledny! Uzyj /email recovery [email] aby wygenerowac nowy.'
diff --git a/src/main/resources/messages/messages_ro.yml b/src/main/resources/messages/messages_ro.yml
new file mode 100644
index 000000000..c872fe287
--- /dev/null
+++ b/src/main/resources/messages/messages_ro.yml
@@ -0,0 +1,76 @@
+kick_antibot: 'Protectia AntiBot-ului este activata! Trebuie sa astepti cateva minute pentru a intra pe server.'
+unknown_user: '&cNu putem gasi jucatorul in baza de date!'
+unsafe_spawn: '&cLocatia in care esti acum nu este sigura, ai fost teleportat la spawn.'
+not_logged_in: '&cNu te-ai logat!'
+reg_voluntarily: 'Te poti inregista pe server folosind comanda "/register "'
+usage_log: '&cFoloseste: /login pentru a te loga.'
+wrong_pwd: '&cParola gresita!'
+unregistered: '&cTe-ai unregistart cu succes!'
+reg_disabled: '&cInegistrarea in joc nu este activata!'
+valid_session: '&2Te-ai logat cu reconectarea sesiuni.'
+login: '&2Te-ai logat cu succes!'
+vb_nonActiv: '&cContul tau nu este activat, te rugam verifica-ti email-ul!'
+user_regged: '&cCineva este inregistrat cu acest nume!'
+no_perm: '&4Nu ai permisiunea!'
+error: '&4A aparut o eroare, te rugam contacteaza un membru din staff!'
+login_msg: '&cTe rugam sa te autentifici folosind comanda "/login "'
+reg_msg: '&3Te rugam sa te inregistrezi folosind comanda "/register "'
+reg_email_msg: '&3Te rugam sa te inregistrezi folosind comanda "/register "'
+max_reg: '&cTe-ai inregistrat cu prea multe counturi (%reg_count/%max_acc %reg_names) pentru conexiunea ta!'
+usage_reg: '&cFoloseste comanda: /register '
+usage_unreg: '&cFoloseste comanda: /unregister '
+pwd_changed: '&2Parola a fost inregistrata cu succes!'
+user_unknown: '&cAcest jucator nu este inregistrat!'
+password_error: '&cParolele nu corespund, verifica-le din nou!'
+password_error_nick: '&cNu poti folosi numele ca si parola, te rugam incearca alta...'
+password_error_unsafe: '&cParola aleasa nu este sigura, te rugam alege alta...'
+invalid_session: '&cIP-ul tau a fost schimbat si sesiunea ta a expirat!'
+reg_only: '&4Doar jucatori inregistrati pot intra pe server! Te rugam foloseste http://example.ro pentru a te inregistra!'
+logged_in: '&cEsti deja autentificat!'
+logout: '&2Te-ai dezautentificat cu succes!'
+same_nick: '&4Acelasi nume se joaca deja pe server!'
+registered: '&2Te-ai inregistrat cu succes!'
+pass_len: '&cParola ta este prea scurta pentru a te inregistra! Te rugam incearca alta!'
+reload: '&2Configuratiile si baza de date sau reincarcat corect!'
+timeout: '&4A expirat timpul de autentificare si ai fost dat afara de server, te rugam incearca din nou!'
+usage_changepassword: '&cFoloseste comanda: /changepassword '
+name_len: '&4Numele tau este prea scurt pentru a te inregistra!'
+regex: '&4Numele tau contine caractere ilegale. Caractere permise: REG_EX'
+add_email: '&3Te rugam adaugati email-ul la contul tau folosind comanda "/email add "'
+recovery_email: '&3Ti-ai uitat parola? Te rugam foloseste comanda "/email recovery "'
+usage_captcha: '&3Pentru a te autentifica trebuie sa folosesti codul de la captcha, te rugam foloseste comanda "/captcha "'
+wrong_captcha: '&cCod-ul captcha este gresit, te rugam foloseste comanda "/captcha THE_CAPTCHA"!'
+valid_captcha: '&2Cod-ul captcha a fost scris corect!'
+kick_forvip: '&3Un V.I.P a intrat pe server cand era plin!'
+kick_fullserver: '&4Server-ul este plin, te rugam incearca din nou mai tarziu!'
+usage_email_add: '&cFoloseste comanda: /email add '
+usage_email_change: '&cFoloseste comanda: /email change '
+usage_email_recovery: '&cFoloseste comanda: /email recovery '
+new_email_invalid: '&cNoul email este invalid, incearca din nou!'
+old_email_invalid: '&cEmail-ul vechi este invalid, incearca din nou!'
+email_invalid: '&cEmail-ul este invalid, incearca din nou!'
+email_added: '&2Email-ul a fost adaugat cu succes la contul tau!'
+email_confirm: '&cTe rugam confirma adresa de email!'
+email_changed: '&2Email-ul a fost schimbat corect!'
+email_send: ' &2Recuperarea email-ul a fost trimis cu succes! Te rugam sa verificati email-ul in inbox!'
+email_exists: '&cRecuperarea email-ului a fost deja trimisa! Puteti sa-l anulati si sa trimiteti unul nou folosind comanda de mai jos:'
+country_banned: '&4Tara ta este interzisa pe acest server!'
+antibot_auto_enabled: '&4[AntiBotService] AntiBot-ul a fost activat din cauza numărului mare de conexiuni!'
+antibot_auto_disabled: '&2[AntiBotService] AntiBot-ul a fost dezactivat dupa %m de minute!'
+email_already_used: '&4Email-ul a fost deja folosit'
+two_factor_create: '&2Codul tau secret este %code. Il poti scana de aici %url'
+not_owner_error: 'Tu nu esti detinatorul acestui cont. Te rugam alege alt nume!'
+invalid_name_case: 'Ar trebui sa intri cu numele %valid nu %invalid'
+denied_command: '&cPentru a folosi comanda trebuie sa te autentifici!'
+same_ip_online: 'Un jucator cu acelasi IP joaca deja!'
+denied_chat: 'Pentru a folosi chat-ul trebuie sa te autentifici!'
+password_error_chars: '&4Parola ta contine caractere ilegale. Caractere permise: REG_EX'
+email_show: '&2Adresa ta curenta de email este: &f%email'
+show_no_email: '&2Nu ai nici-o adresa de email asociat cu acest cont.'
+tempban_max_logins: '&cAi fost interzis temporar deoarece ai incercat sa te autentifici de prea multe ori.'
+accounts_owned_self: 'Detii %count conturi:'
+accounts_owned_other: 'Jucatorul %name are %count conturi:'
+kicked_admin_registered: 'Un administrator tocmai te-a inregistrat, te rog autentifica-te din nou.'
+incomplete_email_settings: 'Eroare: nu toate setarile necesare pentru trimiterea email-ului sunt facute! Te rugam contacteaza un administrator.'
+recovery_code_sent: 'Un cod de recuperare a parolei a fost trimis catre email-ul tau.'
+recovery_code_incorrect: 'Codul de recuperare nu este corect! Foloseste /email recovery [email] pentru a genera unul nou.'
diff --git a/src/main/resources/messages/messages_ru.yml b/src/main/resources/messages/messages_ru.yml
index 01374ae89..f37f3a41e 100644
--- a/src/main/resources/messages/messages_ru.yml
+++ b/src/main/resources/messages/messages_ru.yml
@@ -72,7 +72,7 @@ kicked_admin_registered: 'Администратор зарегистриров
tempban_max_logins: '&cВы были временно забанены, потому что вы пытались войти в систему слишком много раз.'
accounts_owned_self: 'Вы являетесь владельцем %count аккаунтов:'
incomplete_email_settings: 'Ошибка: не все необходимые параметры установлены для отправки электронной почты. Пожалуйста, обратитесь к администратору.'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
-# 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'
\ No newline at end of file
+email_show: '&2Ваш текущий адрес электронной почты: &f%email'
+show_no_email: '&2В данный момент к вашему аккаунте не привязана электронная почта.'
+recovery_code_sent: 'Код восстановления для сброса пароля был отправлен на вашу электронную почту.'
+recovery_code_incorrect: 'Код восстановления неверный! Введите /email recovery [email], чтобы отправить новый код'
diff --git a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java
index ba7f76068..3b5432bf6 100644
--- a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java
+++ b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java
@@ -19,9 +19,8 @@ import fr.xephi.authme.task.purge.PurgeService;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.plugin.PluginDescriptionFile;
-import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.PluginManager;
-import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.plugin.java.JavaPluginLoader;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -29,13 +28,12 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
-import static fr.xephi.authme.settings.TestSettingsMigrationServices.alwaysFulfilled;
import static fr.xephi.authme.settings.properties.AuthMeSettingsRetriever.buildConfigurationData;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@@ -50,9 +48,6 @@ import static org.mockito.Mockito.mock;
@RunWith(MockitoJUnitRunner.class)
public class AuthMeInitializationTest {
- @Mock
- private PluginLoader pluginLoader;
-
@Mock
private Server server;
@@ -61,7 +56,6 @@ public class AuthMeInitializationTest {
private AuthMe authMe;
private File dataFolder;
- private File settingsFile;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -74,13 +68,13 @@ public class AuthMeInitializationTest {
@Before
public void initAuthMe() throws IOException {
dataFolder = temporaryFolder.newFolder();
- settingsFile = new File(dataFolder, "config.yml");
+ File settingsFile = new File(dataFolder, "config.yml");
+ JavaPluginLoader pluginLoader = new JavaPluginLoader(server);
Files.copy(TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "config.test.yml"), settingsFile);
// Mock / wire various Bukkit components
given(server.getLogger()).willReturn(mock(Logger.class));
ReflectionTestUtils.setField(Bukkit.class, null, "server", server);
- given(server.getScheduler()).willReturn(mock(BukkitScheduler.class));
given(server.getPluginManager()).willReturn(pluginManager);
// PluginDescriptionFile is final: need to create a sample one
@@ -88,14 +82,14 @@ public class AuthMeInitializationTest {
"AuthMe", "N/A", AuthMe.class.getCanonicalName());
// Initialize AuthMe
- authMe = new AuthMe(pluginLoader, server, descriptionFile, dataFolder, null);
+ authMe = new AuthMe(pluginLoader, descriptionFile, dataFolder, null);
}
@Test
public void shouldInitializeAllServices() {
// given
Settings settings =
- new Settings(dataFolder, mock(PropertyResource.class), alwaysFulfilled(), buildConfigurationData());
+ new Settings(dataFolder, mock(PropertyResource.class), null, buildConfigurationData());
Injector injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
injector.provide(DataFolder.class, dataFolder);
diff --git a/src/test/java/fr/xephi/authme/ConsoleLoggerTest.java b/src/test/java/fr/xephi/authme/ConsoleLoggerTest.java
index 6ae87df63..8eae45ec2 100644
--- a/src/test/java/fr/xephi/authme/ConsoleLoggerTest.java
+++ b/src/test/java/fr/xephi/authme/ConsoleLoggerTest.java
@@ -12,7 +12,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
@@ -26,8 +26,8 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
diff --git a/src/test/java/fr/xephi/authme/TestHelper.java b/src/test/java/fr/xephi/authme/TestHelper.java
index d16bd31f7..5017c4769 100644
--- a/src/test/java/fr/xephi/authme/TestHelper.java
+++ b/src/test/java/fr/xephi/authme/TestHelper.java
@@ -18,8 +18,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
diff --git a/src/test/java/fr/xephi/authme/api/NewAPITest.java b/src/test/java/fr/xephi/authme/api/NewAPITest.java
index 02dfbec26..cc3dd1882 100644
--- a/src/test/java/fr/xephi/authme/api/NewAPITest.java
+++ b/src/test/java/fr/xephi/authme/api/NewAPITest.java
@@ -18,7 +18,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
diff --git a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java
index cfcb00f55..4e0c43af2 100644
--- a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java
@@ -14,7 +14,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import java.util.Collections;
@@ -29,18 +29,18 @@ import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
/**
* Test for {@link CommandHandler}.
@@ -85,7 +85,7 @@ public class CommandHandlerTest {
given(injector.newInstance(any(Class.class))).willAnswer(new Answer