Merge branch 'master' into 745-captcha-login-message

This commit is contained in:
Alexandre Vanhecke 2016-12-12 17:58:37 +01:00 committed by GitHub
commit fae7286776
267 changed files with 4903 additions and 3436 deletions

View File

@ -1,32 +1,28 @@
<p align="center"><img src="http://i61.tinypic.com/291dm49.png"></p> <p align="center"><img src="http://i61.tinypic.com/291dm49.png"></p>
<p align="center"><strong>The most used authentication plugin for CraftBukkit/Spigot!</strong></p> <p align="center"><strong>The most used authentication plugin for Spigot and CraftBukkit!</strong></p>
<hr> <hr>
#####Development tools: #####Links and Contacts:
- MAIN REPO (**release sources, issue tracker!**): [Github Main Page](https://github.com/Xephi/AuthMeReloaded) - GitHub pages:
- [Main](https://github.com/Xephi/AuthMeReloaded) (**release sources, issue tracker!**)
- [Development](https://github.com/AuthMe/AuthMeReloaded) (**latest sources, please send PRs here!**):
- DEVELOPMENT TEAM REPO (**latest sources, please send PRs here!**): [Github Development Page](https://github.com/AuthMe/AuthMeReloaded) - Contacts:
- [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- Developers ChatRoom: [![Join the chat at https://gitter.im/Xephi/AuthMeReloaded](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - CI Services:
- [Official Jenkins](http://ci.xephi.fr/job/AuthMeReloaded) (**DEVELOPMENT BUILDS**)
- Travis CI: [![Travis CI](https://travis-ci.org/AuthMe/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/AuthMe/AuthMeReloaded)
- CircleCI: [![CircleCI](https://circleci.com/gh/AuthMe/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/AuthMe/AuthMeReloaded)
- Build Server (**DEVELOPMENT BUILDS**): [Xephi's Jenkins](http://ci.xephi.fr/job/AuthMeReloaded) - Project status:
- Dependencies: [![Dependencies status](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d/badge.svg)](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
- Test coverage: [![Coverage status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
- Build status: [![Build Status](https://travis-ci.org/AuthMe/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/AuthMe/AuthMeReloaded) - Development resources:
- <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">JavaDocs</a>
- Dependencies: [![Dependency Status](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d/badge.svg)](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d) - <a href="http://ci.xephi.fr/plugin/repository/everything/">Maven Repository</a>
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/AuthMe/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/AuthMe/AuthMeReloaded)
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
- JitPack (just in case): [![](https://jitpack.io/v/AuthMe/AuthMeReloaded.svg)](https://jitpack.io/#AuthMe/AuthMeReloaded)
- Code Coverage: [![Coverage Status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
- Issue Tracking : [![Stories in Ready](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=ready&title=Ready)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in Bugs](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=bugs&title=Bugs)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in In%20Progress](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=in%20progress&title=In%20Progress)](https://waffle.io/Xephi/AuthMeReloaded)
- JavaDoc: <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">AuthMe Javadoc</a>
- Maven Repo: <a href="http://ci.xephi.fr/plugin/repository/everything/">AuthMe Repo</a>
#####Statistics: #####Statistics:
@ -38,25 +34,21 @@ McStats: http://mcstats.org/plugin/AuthMe
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png"> <img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
#####Development history:
Outdated!
[![Gource AuthMe History Video](http://img.youtube.com/vi/hJRzNfYyd9k/hqdefault.jpg)](https://www.youtube.com/watch?v=hJRzNfYyd9k)
<hr> <hr>
#####Compiling Requirements: #####Compiling requirements:
>- JDK 1.8 >- JDK 1.8
>- Maven >- Maven
>- Git/Github (Optional) >- Git/Github (Optional)
#####How to compile the project: #####How to compile the project:
>- Clone the project with Git/Github >- Clone the project with Git/Github
>- Execute command "mvn clean install" >- Execute command "mvn clean package"
#####Running Requirements: #####Running requirements:
>- Java 1.8 >- Java 1.8
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X) >- TacoSpigot, PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X, 1.11.X)
>- ProtocolLib (optional, required by the protectInventory feature) >- ProtocolLib (optional, required by some features)
<hr> <hr>
###Plugin Description: ###Plugin Description:
@ -102,19 +94,19 @@ You can also create your own translation file and, if you want, you can share it
</ul></li> </ul></li>
<li>Custom MySQL tables/columns names (useful with forums databases)</li> <li>Custom MySQL tables/columns names (useful with forums databases)</li>
<li><strong>Cached database queries!</strong></li> <li><strong>Cached database queries!</strong></li>
<li><strong>Fully compatible with Citizens2, CombatTag, CombatTagPlus and ChestShop!</strong></li> <li><strong>Fully compatible with Citizens2, CombatTag, CombatTagPlus!</strong></li>
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li> <li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
<li>Restricted users (associate a Username with an IP)</li> <li>Restricted users (associate a username with an IP)</li>
<li>Protect player's inventory until a correct Authentication</li> <li>Protect player's inventory until correct authentication (requires ProtocolLib)</li>
<li>Saves the quit location of the player</li> <li>Saves the quit location of the player</li>
<li>Automatic database Backup</li> <li>Automatic database backup</li>
<li>Available languages: en, de, br, cz, pl, fr, uk, ru, hu, sk, es, fi, zhtw, zhhk, zhcn, lt, it, ko, pt, nl, gl, bg, eu, tr, vn (feel free to send new translations)</li> <li>Available languages: <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md">translations</a></li>
<li>Built-in Deprecated FlatFile (auths.db) to SQL (authme.sql) converter!</li> <li>Built-in Deprecated FlatFile (auths.db) to SQL (authme.sql) converter!</li>
<li><strong>Import your old database from other plugins like Rakamak, xAuth, CrazyLogin, RoyalAuth and vAuth!</strong></li> <li><strong>Import your old database from other plugins like Rakamak, xAuth, CrazyLogin, RoyalAuth and vAuth!</strong></li>
</ul> </ul>
####Configuration ####Configuration
<a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/configure-auth-me/">How to Configure Authme</a> <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/config.md">How to configure Authme</a>
####Email Recovery Dependency ####Email Recovery Dependency
<a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-configure-email-recovery-system/">How to configure email recovery system?</a> <a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-configure-email-recovery-system/">How to configure email recovery system?</a>
####Commands ####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) - [List of all permission nodes](http://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md)
####How To ####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/) - [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/) - [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/) - [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
<hr> <hr>
#####GeoIP
This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com
<hr>
#####Donate
<p>Do you like our work? Do you want to buy us a coffee? :)<br>
EUR: <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=QLMM9SNCX825Y"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif"></a>
USD: <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=PWQMYCP2SAH6L"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif"></a></p>
#####Sponsor #####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.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) [![GameHosting](http://www.gamehosting.it/images/bn3.png)](http://www.gamehosting.it)
#####Credits #####Credits
<p>Team members: look at the <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/team.txt">team.txt file</a> <p>Team members: look at the <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/team.txt">member list</a>
<p>Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka</p> <p>Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka</p>
<p>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p> <p>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p>
#####GeoIP License
This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com

View File

@ -11,6 +11,8 @@ test:
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS - cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-legacy.jar $CIRCLE_ARTIFACTS - cp ./target/AuthMe-*-SNAPSHOT-legacy.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS/AuthMe.jar - 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: notify:
webhooks: webhooks:
- url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf - url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly --> <!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Oct 16 21:39:08 CEST 2016. See commands/commands.tpl.md --> <!-- File auto-generated on Sun Oct 23 18:25:12 CEST 2016. See docs/commands/commands.tpl.md -->
## AuthMe Commands ## AuthMe Commands
You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` 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** &lt;oldPassword> &lt;newPassword>: Command to change your password using AuthMeReloaded. - **/changepassword** &lt;oldPassword> &lt;newPassword>: Command to change your password using AuthMeReloaded.
<br />Requires `authme.player.changepassword` <br />Requires `authme.player.changepassword`
- **/changepassword help** [query]: View detailed help for /changepassword commands. - **/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** &lt;email> &lt;verifyEmail>: Add a new email address to your account. - **/email add** &lt;email> &lt;verifyEmail>: Add a new email address to your account.
<br />Requires `authme.player.email.add` <br />Requires `authme.player.email.add`
- **/email change** &lt;oldEmail> &lt;newEmail>: Change an email address of your account. - **/email change** &lt;oldEmail> &lt;newEmail>: Change an email address of your account.
@ -75,7 +76,6 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
<br />Requires `authme.player.captcha` <br />Requires `authme.player.captcha`
- **/captcha help** [query]: View detailed help for /captcha commands. - **/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

467
docs/config.md Normal file
View File

@ -0,0 +1,467 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Nov 13 13:34:49 CET 2016. See docs/config/config.tpl.md -->
## 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 <password> <confirmPassword>
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 <email> <confirmEmail>
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

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly --> <!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sat Oct 01 23:42:20 CEST 2016. See hashmethods/hash_algorithms.tpl.md --> <!-- File auto-generated on Fri Nov 25 15:48:35 CET 2016. See docs/hashmethods/hash_algorithms.tpl.md -->
## Hash Algorithms ## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely. 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 | | DOUBLEMD5 | Do not use | 32 | | | None | |
IPB3 | Acceptable | 32 | | | Text | 5 | Y IPB3 | Acceptable | 32 | | | Text | 5 | Y
IPB4 | Does not work | 60 | | | Text | 22 | 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 | | MD5 | Do not use | 32 | | | None | |
MD5VB | Acceptable | 56 | | | Text | 16 | MD5VB | Acceptable | 56 | | | Text | 16 |
MYBB | Acceptable | 32 | | | Text | 8 | Y MYBB | Acceptable | 32 | | | Text | 8 | Y
PBKDF2 | Does not work | 332 | | | Text | 12 | PBKDF2 | Recommended | 165 | | | Text | 16 |
PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 | PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 |
PHPBB | Acceptable | 34 | | | Text | 16 | PHPBB | Acceptable | 34 | | | Text | 16 |
PHPFUSION | Do not use | 64 | Y | | | | Y 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

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly --> <!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Oct 16 21:39:10 CEST 2016. See permissions/permission_nodes.tpl.md --> <!-- File auto-generated on Sun Oct 23 15:38:58 CEST 2016. See permissions/permission_nodes.tpl.md -->
## AuthMe Permission Nodes ## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds. 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** Grants all email permissions.
- **authme.player.email.add** Command permission to add an email address. - **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.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.login** Command permission to login.
- **authme.player.logout** Command permission to logout. - **authme.player.logout** Command permission to logout.
- **authme.player.register** Command permission to register. - **authme.player.register** Command permission to register.
- **authme.player.seeownaccounts** Permission to use to see own other accounts. - **authme.player.seeownaccounts** Permission to use to see own other accounts.
- **authme.player.unregister** Command permission to unregister. - **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

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly --> <!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Oct 09 09:42:48 CEST 2016. See translations/translations.tpl.md --> <!-- File auto-generated on Sun Dec 11 08:16:38 CET 2016. See docs/translations/translations.tpl.md -->
# AuthMe Translations # AuthMe Translations
The following translations are available in AuthMe. Set `messagesLanguage` to the language code 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 | &nbsp; Code | Language | Translated | &nbsp;
---- | -------- | ---------: | ------ ---- | -------- | ---------: | ------
[en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" /> [en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 73% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=73&h=5&txtpad=1" alt="bar" /> [bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 71% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=71&h=5&txtpad=1" alt="bar" />
[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" /> [br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 91% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=91&h=5&txtpad=1" alt="bar" /> [cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&h=5&txtpad=1" alt="bar" />
[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 97% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=97&h=5&txtpad=1" alt="bar" /> [de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 95% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=77dd44&w=95&h=5&txtpad=1" alt="bar" />
[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" /> [es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 66% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=66&h=5&txtpad=1" alt="bar" /> [eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 64% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=64&h=5&txtpad=1" alt="bar" />
[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 70% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=70&h=5&txtpad=1" alt="bar" /> [fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 68% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=68&h=5&txtpad=1" alt="bar" />
[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 97% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=97&h=5&txtpad=1" alt="bar" /> [fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 95% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=77dd44&w=95&h=5&txtpad=1" alt="bar" />
[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 74% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=74&h=5&txtpad=1" alt="bar" /> [gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&h=5&txtpad=1" alt="bar" />
[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" /> [hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 74% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=74&h=5&txtpad=1" alt="bar" /> [id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&h=5&txtpad=1" alt="bar" />
[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" /> [it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 76% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb9900&w=76&h=5&txtpad=1" alt="bar" /> [ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 74% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=74&h=5&txtpad=1" alt="bar" />
[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 57% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb6600&w=57&h=5&txtpad=1" alt="bar" /> [lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 55% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb6600&w=55&h=5&txtpad=1" alt="bar" />
[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 80% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=80&h=5&txtpad=1" alt="bar" /> [nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 78% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb9900&w=78&h=5&txtpad=1" alt="bar" />
[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 95% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=77dd44&w=95&h=5&txtpad=1" alt="bar" /> [pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 91% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=91&h=5&txtpad=1" alt="bar" /> [pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&h=5&txtpad=1" alt="bar" />
[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 97% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=97&h=5&txtpad=1" alt="bar" /> [ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 50% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb6600&w=50&h=5&txtpad=1" alt="bar" /> [ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 85% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=85&h=5&txtpad=1" alt="bar" /> [sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 49% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa5500&w=49&h=5&txtpad=1" alt="bar" />
[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 97% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=97&h=5&txtpad=1" alt="bar" /> [tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 85% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=85&h=5&txtpad=1" alt="bar" /> [uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 95% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=77dd44&w=95&h=5&txtpad=1" alt="bar" />
[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 85% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=85&h=5&txtpad=1" alt="bar" /> [vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 85% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=85&h=5&txtpad=1" alt="bar" /> [zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 85% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=85&h=5&txtpad=1" alt="bar" /> [zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
--- ---
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

27
pom.xml
View File

@ -62,7 +62,7 @@
<bukkitplugin.authors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008</bukkitplugin.authors> <bukkitplugin.authors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008</bukkitplugin.authors>
<!-- Change Bukkit Version HERE! --> <!-- Change Bukkit Version HERE! -->
<bukkit.version>1.10.2-R0.1-SNAPSHOT</bukkit.version> <bukkit.version>1.11-R0.1-SNAPSHOT</bukkit.version>
</properties> </properties>
<!-- Jenkins profile --> <!-- Jenkins profile -->
@ -196,7 +196,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.6.0</version>
<configuration> <configuration>
<source>${project.jdkVersion}</source> <source>${project.jdkVersion}</source>
<target>${project.jdkVersion}</target> <target>${project.jdkVersion}</target>
@ -268,6 +268,10 @@
<pattern>net.ricecode.similarity</pattern> <pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern> <shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>de.rtner</pattern>
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
</relocation>
<relocation> <relocation>
<pattern>javax.inject</pattern> <pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern> <shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
@ -319,6 +323,10 @@
<pattern>net.ricecode.similarity</pattern> <pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern> <shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>de.rtner</pattern>
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
</relocation>
<relocation> <relocation>
<pattern>javax.inject</pattern> <pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern> <shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
@ -524,6 +532,13 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- PBKDF2 implementation -->
<dependency>
<groupId>de.rtner</groupId>
<artifactId>PBKDF2</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ --> <!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
<!-- Moved in profiles! --> <!-- Moved in profiles! -->
@ -873,7 +888,7 @@
<dependency> <dependency>
<groupId>com.github.authme</groupId> <groupId>com.github.authme</groupId>
<artifactId>configme</artifactId> <artifactId>configme</artifactId>
<version>0.2</version> <version>0.2.1</version>
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
<exclusions> <exclusions>
@ -904,7 +919,7 @@
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<scope>test</scope> <scope>test</scope>
<version>2.0.5-beta</version> <version>2.2.27</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>hamcrest-core</artifactId> <artifactId>hamcrest-core</artifactId>
@ -917,13 +932,13 @@
<dependency> <dependency>
<groupId>org.xerial</groupId> <groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId> <artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version> <version>3.15.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
<version>1.4.192</version> <version>1.4.193</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>

View File

@ -109,7 +109,6 @@ abstract class AuthMeController {
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist) * @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/ */
private function getHashFromDatabase($username) { private function getHashFromDatabase($username) {
// Add here your database host, username, password and database name
$mysqli = $this->getAuthmeMySqli(); $mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) { if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?'); $stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');

View File

@ -0,0 +1,53 @@
<?php
/***********************************************************
* AuthMe website integration logic for PBKDF2 *
* ------------------------------------------------------- *
* See AuthMeController for details. *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
***********************************************************/
class Pbkdf2 extends AuthMeController {
/** @var string[] range of characters for salt generation */
private $CHARS;
const SALT_LENGTH = 16;
const NUMBER_OF_ITERATIONS = 10000;
public function __construct() {
$this->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'));
}
}

View File

@ -15,7 +15,7 @@ class Sha256 extends AuthMeController {
const SALT_LENGTH = 16; const SALT_LENGTH = 16;
public function __construct() { public function __construct() {
$this->CHARS = self::initRandomChars(); $this->CHARS = self::initCharRange();
} }
protected function isValidPassword($password, $hash) { protected function isValidPassword($password, $hash) {
@ -41,7 +41,7 @@ class Sha256 extends AuthMeController {
return $salt; return $salt;
} }
private static function initRandomChars() { private static function initCharRange() {
return array_merge(range('0', '9'), range('a', 'f')); return array_merge(range('0', '9'), range('a', 'f'));
} }

View File

@ -5,44 +5,45 @@ import ch.jalu.injector.InjectorBuilder;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.api.API; import fr.xephi.authme.api.API;
import fr.xephi.authme.api.NewAPI; import fr.xephi.authme.api.NewAPI;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.command.CommandHandler;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.Initializer; import fr.xephi.authme.initialization.DataSourceProvider;
import fr.xephi.authme.initialization.MetricsManager;
import fr.xephi.authme.initialization.OnShutdownPlayerSaver; 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.initialization.TaskCloser;
import fr.xephi.authme.listener.BlockListener; import fr.xephi.authme.listener.BlockListener;
import fr.xephi.authme.listener.EntityListener; import fr.xephi.authme.listener.EntityListener;
import fr.xephi.authme.listener.PlayerListener; import fr.xephi.authme.listener.PlayerListener;
import fr.xephi.authme.listener.PlayerListener111;
import fr.xephi.authme.listener.PlayerListener16; import fr.xephi.authme.listener.PlayerListener16;
import fr.xephi.authme.listener.PlayerListener18; import fr.xephi.authme.listener.PlayerListener18;
import fr.xephi.authme.listener.PlayerListener19; import fr.xephi.authme.listener.PlayerListener19;
import fr.xephi.authme.listener.ServerListener; import fr.xephi.authme.listener.ServerListener;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PermissionsSystemType; import fr.xephi.authme.permission.PermissionsSystemType;
import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.security.crypts.SHA256;
import fr.xephi.authme.service.BackupService; import fr.xephi.authme.service.BackupService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService; import fr.xephi.authme.service.GeoIpService;
import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.CleanupTask; import fr.xephi.authme.task.CleanupTask;
import fr.xephi.authme.task.purge.PurgeService; 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 fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import java.io.File; import java.io.File;
@ -60,7 +61,7 @@ public class AuthMe extends JavaPlugin {
private static final String LOG_FILENAME = "authme.log"; private static final String LOG_FILENAME = "authme.log";
private static final int CLEANUP_INTERVAL = 5 * TICKS_PER_MINUTE; 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 pluginVersion = "N/D";
private static String pluginBuildNumber = "Unknown"; private static String pluginBuildNumber = "Unknown";
@ -68,7 +69,6 @@ public class AuthMe extends JavaPlugin {
private CommandHandler commandHandler; private CommandHandler commandHandler;
private PermissionsManager permsMan; private PermissionsManager permsMan;
private Settings settings; private Settings settings;
private Messages messages;
private DataSource database; private DataSource database;
private BukkitService bukkitService; private BukkitService bukkitService;
private Injector injector; private Injector injector;
@ -86,9 +86,8 @@ public class AuthMe extends JavaPlugin {
*/ */
@VisibleForTesting @VisibleForTesting
@SuppressWarnings("deprecation") // the super constructor is deprecated to mark it for unit testing only @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, protected AuthMe(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
final File dataFolder, final File file) { super(loader, description, dataFolder, file);
super(loader, server, description, dataFolder, file);
} }
/** /**
@ -133,7 +132,7 @@ public class AuthMe extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// Load the plugin version data from the plugin description file // Load the plugin version data from the plugin description file
loadPluginInfo(); loadPluginInfo(getDescription().getVersion());
// Initialize the plugin // Initialize the plugin
try { try {
@ -156,7 +155,7 @@ public class AuthMe extends JavaPlugin {
new BackupService(this, settings).doBackup(BackupService.BackupCause.START); new BackupService(this, settings).doBackup(BackupService.BackupCause.START);
// Set up Metrics // Set up Metrics
MetricsManager.sendMetrics(this, settings); OnStartupTasks.sendMetrics(this, settings);
// Sponsor messages // Sponsor messages
ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); 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. * 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() { private static void loadPluginInfo(String versionRaw) {
String versionRaw = this.getDescription().getVersion();
int index = versionRaw.lastIndexOf("-"); int index = versionRaw.lastIndexOf("-");
if (index != -1) { if (index != -1) {
pluginVersion = versionRaw.substring(0, index); pluginVersion = versionRaw.substring(0, index);
@ -191,10 +191,8 @@ public class AuthMe extends JavaPlugin {
/** /**
* Initialize the plugin and all the services. * 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 // Set the Logger instance and log file path
ConsoleLogger.setLogger(getLogger()); ConsoleLogger.setLogger(getLogger());
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME)); ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
@ -202,40 +200,30 @@ public class AuthMe extends JavaPlugin {
// Create plugin folder // Create plugin folder
getDataFolder().mkdir(); getDataFolder().mkdir();
// Load settings and set up the console and console filter // Create injector, provide elements from the Bukkit environment and register providers
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
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create(); injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
// Register elements of the Bukkit / JavaPlugin environment
injector.register(AuthMe.class, this); injector.register(AuthMe.class, this);
injector.register(Server.class, getServer()); injector.register(Server.class, getServer());
injector.register(PluginManager.class, getServer().getPluginManager()); injector.register(PluginManager.class, getServer().getPluginManager());
injector.register(BukkitScheduler.class, getServer().getScheduler()); injector.register(BukkitScheduler.class, getServer().getScheduler());
injector.provide(DataFolder.class, getDataFolder()); injector.provide(DataFolder.class, getDataFolder());
injector.registerProvider(Settings.class, SettingsProvider.class);
injector.registerProvider(DataSource.class, DataSourceProvider.class);
// Register elements we instantiate manually // Get settings and set up logger
injector.register(Settings.class, settings); settings = injector.getSingleton(Settings.class);
injector.register(DataSource.class, database); ConsoleLogger.setLoggingOptions(settings);
injector.register(BukkitService.class, bukkitService); OnStartupTasks.setupConsoleFilter(settings, getLogger());
// Set all service fields on the AuthMe class
instantiateServices(injector); instantiateServices(injector);
// Convert deprecated PLAINTEXT hash entries
MigrationService.changePlainTextToSha256(settings, database, new SHA256());
// TODO: does this still make sense? -sgdc3 // TODO: does this still make sense? -sgdc3
// If the server is empty (fresh start) just set all the players as unlogged // 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(); database.purgeLogged();
} }
@ -243,7 +231,8 @@ public class AuthMe extends JavaPlugin {
registerEventListeners(injector); registerEventListeners(injector);
// Start Email recall task if needed // 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(); playerCache = PlayerCache.getInstance();
injector.register(PlayerCache.class, playerCache); injector.register(PlayerCache.class, playerCache);
messages = injector.getSingleton(Messages.class); database = injector.getSingleton(DataSource.class);
permsMan = injector.getSingleton(PermissionsManager.class); permsMan = injector.getSingleton(PermissionsManager.class);
bukkitService = injector.getSingleton(BukkitService.class); bukkitService = injector.getSingleton(BukkitService.class);
commandHandler = injector.getSingleton(CommandHandler.class); commandHandler = injector.getSingleton(CommandHandler.class);
@ -312,6 +301,11 @@ public class AuthMe extends JavaPlugin {
if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) { if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) {
pluginManager.registerEvents(injector.getSingleton(PlayerListener19.class), this); 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 // Wait for tasks and close data source
new Thread( new TaskCloser(this, database).run();
new TaskCloser(this, database),
"AuthMe-DataSource#close"
).start();
// Disabled correctly // Disabled correctly
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!"); ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");

View File

@ -19,12 +19,13 @@ import javax.inject.Inject;
/** /**
* Deprecated API of AuthMe. Please use {@link NewAPI} instead. * Deprecated API of AuthMe. Please use {@link NewAPI} instead.
*
* @deprecated Use {@link NewAPI}
*/ */
@Deprecated @Deprecated
public class API { public class API {
public static final String newline = System.getProperty("line.separator"); private static AuthMe instance;
public static AuthMe instance;
private static DataSource dataSource; private static DataSource dataSource;
private static PasswordSecurity passwordSecurity; private static PasswordSecurity passwordSecurity;
private static Management management; private static Management management;
@ -83,28 +84,17 @@ public class API {
} }
public static Location getLastLocation(Player player) { 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) { if (auth != null) {
Location loc = new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ()); return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
return loc;
} else {
return null;
}
} catch (NullPointerException ex) {
return null;
} }
return null;
} }
public static void setPlayerInventory(Player player, ItemStack[] content, public static void setPlayerInventory(Player player, ItemStack[] content, ItemStack[] armor) {
ItemStack[] armor) { player.getInventory().setContents(content);
try { player.getInventory().setArmorContents(armor);
player.getInventory().setContents(content);
player.getInventory().setArmorContents(armor);
} catch (NullPointerException ignored) {
}
} }
/** /**

View File

@ -25,8 +25,8 @@ import java.util.List;
*/ */
public class NewAPI { public class NewAPI {
public static NewAPI singleton; private static NewAPI singleton;
public final AuthMe plugin; private final AuthMe plugin;
private final PluginHookService pluginHookService; private final PluginHookService pluginHookService;
private final DataSource dataSource; private final DataSource dataSource;
private final PasswordSecurity passwordSecurity; private final PasswordSecurity passwordSecurity;

View File

@ -87,10 +87,10 @@ public class CommandMapper {
return classes; return classes;
} }
private FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) { private static FoundCommandResult getCommandWithSmallestDifference(CommandDescription base, List<String> parts) {
// Return the base command with incorrect arg count error if we only have one part // Return the base command with incorrect arg count error if we only have one part
if (parts.size() <= 1) { if (parts.size() <= 1) {
return new FoundCommandResult(base, parts, new ArrayList<String>(), 0.0, INCORRECT_ARGUMENTS); return new FoundCommandResult(base, parts, new ArrayList<>(), 0.0, INCORRECT_ARGUMENTS);
} }
final String childLabel = parts.get(1); final String childLabel = parts.get(1);
@ -115,7 +115,7 @@ public class CommandMapper {
final int partsSize = parts.size(); final int partsSize = parts.size();
List<String> labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize)); List<String> labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize));
List<String> arguments = (labels.size() == partsSize) List<String> arguments = (labels.size() == partsSize)
? new ArrayList<String>() ? new ArrayList<>()
: parts.subList(labels.size(), partsSize); : parts.subList(labels.size(), partsSize);
return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status); 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 * @return A command if there was a complete match (including proper argument count), null otherwise
*/ */
private CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) { private static CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
if (CollectionUtils.isEmpty(parts)) { if (CollectionUtils.isEmpty(parts)) {
return null; return null;
} }

View File

@ -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 <T> The type of the property
* @return The property's value
*/
public <T> T getProperty(Property<T> 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);
}
}

View File

@ -1,11 +1,11 @@
package fr.xephi.authme.command.executable.authme; 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.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -23,7 +23,7 @@ public class AccountsCommand implements ExecutableCommand {
private BukkitService bukkitService; private BukkitService bukkitService;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments) { public void executeCommand(final CommandSender sender, List<String> arguments) {
@ -50,13 +50,13 @@ public class AccountsCommand implements ExecutableCommand {
public void run() { public void run() {
PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase()); PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase());
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commonService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }
List<String> accountList = dataSource.getAllAuthsByIp(auth.getIp()); List<String> accountList = dataSource.getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) { if (accountList.isEmpty()) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED); commonService.send(sender, MessageKey.USER_NOT_REGISTERED);
} else if (accountList.size() == 1) { } else if (accountList.size() == 1) {
sender.sendMessage("[AuthMe] " + playerName + " is a single account player"); sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
} else { } else {

View File

@ -1,15 +1,15 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; 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.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService; import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult; import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -38,7 +38,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
private ValidationService validationService; private ValidationService validationService;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments) { public void executeCommand(final CommandSender sender, List<String> arguments) {
@ -49,38 +49,45 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
// Validate the password // Validate the password
ValidationResult validationResult = validationService.validatePassword(playerPass, playerName); ValidationResult validationResult = validationService.validatePassword(playerPass, playerName);
if (validationResult.hasError()) { if (validationResult.hasError()) {
commandService.send(sender, validationResult.getMessageKey(), validationResult.getArgs()); commonService.send(sender, validationResult.getMessageKey(), validationResult.getArgs());
return; return;
} }
// Set the password // Set the password
final String playerNameLowerCase = playerName.toLowerCase(); bukkitService.runTaskOptionallyAsync(() -> changePassword(playerName.toLowerCase(), playerPass, sender));
bukkitService.runTaskOptionallyAsync(new Runnable() { }
@Override /**
public void run() { * Changes the password of the given player to the given password.
PlayerAuth auth = null; *
if (playerCache.isAuthenticated(playerNameLowerCase)) { * @param nameLowercase the name of the player
auth = playerCache.getAuth(playerNameLowerCase); * @param password the password to set
} else if (dataSource.isAuthAvailable(playerNameLowerCase)) { * @param sender the sender initiating the password change
auth = dataSource.getAuth(playerNameLowerCase); */
} private void changePassword(String nameLowercase, String password, CommandSender sender) {
if (auth == null) { PlayerAuth auth = getAuth(nameLowercase);
commandService.send(sender, MessageKey.UNKNOWN_USER); if (auth == null) {
return; commonService.send(sender, MessageKey.UNKNOWN_USER);
} return;
}
HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase); HashedPassword hashedPassword = passwordSecurity.computeHash(password, nameLowercase);
auth.setPassword(hashedPassword); auth.setPassword(hashedPassword);
if (dataSource.updatePassword(auth)) { if (dataSource.updatePassword(auth)) {
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS); commonService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase); ConsoleLogger.info(sender.getName() + " changed password of " + nameLowercase);
} else { } else {
commandService.send(sender, MessageKey.ERROR); 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;
} }
} }

View File

@ -4,7 +4,6 @@ import ch.jalu.injector.Injector;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.converter.Converter; import fr.xephi.authme.datasource.converter.Converter;
import fr.xephi.authme.datasource.converter.CrazyLoginConverter; 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.datasource.converter.xAuthConverter;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -31,7 +31,7 @@ public class ConverterCommand implements ExecutableCommand {
static final Map<String, Class<? extends Converter>> CONVERTERS = getConverters(); static final Map<String, Class<? extends Converter>> CONVERTERS = getConverters();
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private BukkitService bukkitService; private BukkitService bukkitService;
@ -61,7 +61,7 @@ public class ConverterCommand implements ExecutableCommand {
try { try {
converter.execute(sender); converter.execute(sender);
} catch (Exception e) { } catch (Exception e) {
commandService.send(sender, MessageKey.ERROR); commonService.send(sender, MessageKey.ERROR);
ConsoleLogger.logException("Error during conversion:", e); ConsoleLogger.logException("Error during conversion:", e);
} }
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme; 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.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -19,7 +19,7 @@ public class GetEmailCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments) { public void executeCommand(CommandSender sender, List<String> arguments) {
@ -27,7 +27,7 @@ public class GetEmailCommand implements ExecutableCommand {
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commonService.send(sender, MessageKey.UNKNOWN_USER);
} else { } else {
sender.sendMessage("[AuthMe] " + playerName + "'s email: " + auth.getEmail()); sender.sendMessage("[AuthMe] " + playerName + "'s email: " + auth.getEmail());
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme; 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.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -20,16 +20,16 @@ public class LastLoginCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments) { public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the player // 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); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED); commonService.send(sender, MessageKey.USER_NOT_REGISTERED);
return; return;
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.authme; 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.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -19,7 +19,7 @@ public class PurgeLastPositionCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments) { public void executeCommand(final CommandSender sender, List<String> arguments) {
@ -35,7 +35,7 @@ public class PurgeLastPositionCommand implements ExecutableCommand {
// Get the user auth and make sure the user exists // Get the user auth and make sure the user exists
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commonService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }

View File

@ -3,13 +3,13 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.limbo.LimboCache; import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService; import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult; import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -27,7 +27,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
private PasswordSecurity passwordSecurity; private PasswordSecurity passwordSecurity;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@ -51,7 +51,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
// Command logic // Command logic
ValidationResult passwordValidation = validationService.validatePassword(playerPass, playerName); ValidationResult passwordValidation = validationService.validatePassword(playerPass, playerName);
if (passwordValidation.hasError()) { if (passwordValidation.hasError()) {
commandService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs()); commonService.send(sender, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return; return;
} }
@ -60,7 +60,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Override @Override
public void run() { public void run() {
if (dataSource.isAuthAvailable(playerNameLowerCase)) { if (dataSource.isAuthAvailable(playerNameLowerCase)) {
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); commonService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
return; return;
} }
HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase); HashedPassword hashedPassword = passwordSecurity.computeHash(playerPass, playerNameLowerCase);
@ -71,12 +71,12 @@ public class RegisterAdminCommand implements ExecutableCommand {
.build(); .build();
if (!dataSource.saveAuth(auth)) { if (!dataSource.saveAuth(auth)) {
commandService.send(sender, MessageKey.ERROR); commonService.send(sender, MessageKey.ERROR);
return; return;
} }
dataSource.setUnlogged(playerNameLowerCase); dataSource.setUnlogged(playerNameLowerCase);
commandService.send(sender, MessageKey.REGISTER_SUCCESS); commonService.send(sender, MessageKey.REGISTER_SUCCESS);
ConsoleLogger.info(sender.getName() + " registered " + playerName); ConsoleLogger.info(sender.getName() + " registered " + playerName);
final Player player = bukkitService.getPlayerExact(playerName); final Player player = bukkitService.getPlayerExact(playerName);
if (player != null) { if (player != null) {
@ -84,7 +84,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
@Override @Override
public void run() { public void run() {
limboCache.restoreData(player); limboCache.restoreData(player);
player.kickPlayer(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER)); player.kickPlayer(commonService.retrieveSingleMessage(MessageKey.KICK_FOR_ADMIN_REGISTER));
} }
}); });
} }

View File

@ -3,12 +3,12 @@ package fr.xephi.authme.command.executable.authme;
import ch.jalu.injector.Injector; import ch.jalu.injector.Injector;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.initialization.SettingsDependent; import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -35,7 +35,7 @@ public class ReloadCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments) { public void executeCommand(CommandSender sender, List<String> arguments) {
@ -48,7 +48,7 @@ public class ReloadCommand implements ExecutableCommand {
sender.sendMessage("Note: cannot change database type during /authme reload"); sender.sendMessage("Note: cannot change database type during /authme reload");
} }
performReloadOnServices(); performReloadOnServices();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) { } catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting"); sender.sendMessage("Error occurred during reload of AuthMe: aborting");
ConsoleLogger.logException("Aborting! Encountered exception during reload of AuthMe:", e); ConsoleLogger.logException("Aborting! Encountered exception during reload of AuthMe:", e);

View File

@ -1,12 +1,13 @@
package fr.xephi.authme.command.executable.authme; 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.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; 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.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -21,7 +22,7 @@ public class SetEmailCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -29,6 +30,9 @@ public class SetEmailCommand implements ExecutableCommand {
@Inject @Inject
private BukkitService bukkitService; private BukkitService bukkitService;
@Inject
private ValidationService validationService;
@Override @Override
public void executeCommand(final CommandSender sender, List<String> arguments) { public void executeCommand(final CommandSender sender, List<String> arguments) {
// Get the player name and email address // Get the player name and email address
@ -36,8 +40,8 @@ public class SetEmailCommand implements ExecutableCommand {
final String playerEmail = arguments.get(1); final String playerEmail = arguments.get(1);
// Validate the email address // Validate the email address
if (!commandService.validateEmail(playerEmail)) { if (!validationService.validateEmail(playerEmail)) {
commandService.send(sender, MessageKey.INVALID_EMAIL); commonService.send(sender, MessageKey.INVALID_EMAIL);
return; return;
} }
@ -47,17 +51,17 @@ public class SetEmailCommand implements ExecutableCommand {
// Validate the user // Validate the user
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) { if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commonService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} else if (!commandService.isEmailFreeForRegistration(playerEmail, sender)) { } else if (!validationService.isEmailFreeForRegistration(playerEmail, sender)) {
commandService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR); commonService.send(sender, MessageKey.EMAIL_ALREADY_USED_ERROR);
return; return;
} }
// Set the email address // Set the email address
auth.setEmail(playerEmail); auth.setEmail(playerEmail);
if (!dataSource.updateEmail(auth)) { if (!dataSource.updateEmail(auth)) {
commandService.send(sender, MessageKey.ERROR); commonService.send(sender, MessageKey.ERROR);
return; return;
} }
@ -67,7 +71,7 @@ public class SetEmailCommand implements ExecutableCommand {
} }
// Show a status message // Show a status message
commandService.send(sender, MessageKey.EMAIL_CHANGED_SUCCESS); commonService.send(sender, MessageKey.EMAIL_CHANGED_SUCCESS);
} }
}); });
} }

View File

@ -1,11 +1,11 @@
package fr.xephi.authme.command.executable.authme; package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -21,7 +21,7 @@ public class UnregisterAdminCommand implements ExecutableCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private BukkitService bukkitService; private BukkitService bukkitService;
@ -38,7 +38,7 @@ public class UnregisterAdminCommand implements ExecutableCommand {
// Make sure the user exists // Make sure the user exists
if (!dataSource.isAuthAvailable(playerName)) { if (!dataSource.isAuthAvailable(playerName)) {
commandService.send(sender, MessageKey.UNKNOWN_USER); commonService.send(sender, MessageKey.UNKNOWN_USER);
return; return;
} }

View File

@ -1,11 +1,13 @@
package fr.xephi.authme.command.executable.captcha; package fr.xephi.authme.command.executable.captcha;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.CaptchaManager; import fr.xephi.authme.data.CaptchaManager;
import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.limbo.LimboCache; import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -20,7 +22,7 @@ public class CaptchaCommand extends PlayerCommand {
private CaptchaManager captchaManager; private CaptchaManager captchaManager;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private LimboCache limboCache; private LimboCache limboCache;
@ -30,9 +32,9 @@ public class CaptchaCommand extends PlayerCommand {
final String playerName = player.getName().toLowerCase(); final String playerName = player.getName().toLowerCase();
if (playerCache.isAuthenticated(playerName)) { 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)) { } else if (!captchaManager.isCaptchaRequired(playerName)) {
commandService.send(player, MessageKey.USAGE_LOGIN); commonService.send(player, MessageKey.USAGE_LOGIN);
} else { } else {
checkCaptcha(player, arguments.get(0)); checkCaptcha(player, arguments.get(0));
} }
@ -46,7 +48,7 @@ public class CaptchaCommand extends PlayerCommand {
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(false); limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(false);
} else { } else {
String newCode = captchaManager.generateCode(player.getName()); String newCode = captchaManager.generateCode(player.getName());
commandService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode); commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
} }
} }
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.changepassword; 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.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService; import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult; import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -18,7 +18,7 @@ import java.util.List;
public class ChangePasswordCommand extends PlayerCommand { public class ChangePasswordCommand extends PlayerCommand {
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -36,14 +36,14 @@ public class ChangePasswordCommand extends PlayerCommand {
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
if (!playerCache.isAuthenticated(name)) { if (!playerCache.isAuthenticated(name)) {
commandService.send(player, MessageKey.NOT_LOGGED_IN); commonService.send(player, MessageKey.NOT_LOGGED_IN);
return; return;
} }
// Make sure the password is allowed // Make sure the password is allowed
ValidationResult passwordValidation = validationService.validatePassword(newPassword, name); ValidationResult passwordValidation = validationService.validatePassword(newPassword, name);
if (passwordValidation.hasError()) { if (passwordValidation.hasError()) {
commandService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs()); commonService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return; return;
} }

View File

@ -1,9 +1,9 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -18,7 +18,7 @@ public class AddEmailCommand extends PlayerCommand {
private Management management; private Management management;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Override @Override
public void runCommand(Player player, List<String> arguments) { public void runCommand(Player player, List<String> arguments) {
@ -29,7 +29,7 @@ public class AddEmailCommand extends PlayerCommand {
// Closer inspection of the mail address handled by the async task // Closer inspection of the mail address handled by the async task
management.performAddEmail(player, email); management.performAddEmail(player, email);
} else { } else {
commandService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE); commonService.send(player, MessageKey.CONFIRM_EMAIL_MESSAGE);
} }
} }
} }

View File

@ -1,17 +1,17 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; 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.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.util.RandomStringUtils;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.RecoveryCodeService; import fr.xephi.authme.service.RecoveryCodeService;
import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -28,7 +28,7 @@ public class RecoverEmailCommand extends PlayerCommand {
private PasswordSecurity passwordSecurity; private PasswordSecurity passwordSecurity;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@ -49,23 +49,23 @@ public class RecoverEmailCommand extends PlayerCommand {
if (!sendMailSsl.hasAllInformation()) { if (!sendMailSsl.hasAllInformation()) {
ConsoleLogger.warning("Mail API is not set"); ConsoleLogger.warning("Mail API is not set");
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS); commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
return; return;
} }
if (playerCache.isAuthenticated(playerName)) { if (playerCache.isAuthenticated(playerName)) {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); commonService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return; return;
} }
PlayerAuth auth = dataSource.getAuth(playerName); // TODO: Create method to get email only PlayerAuth auth = dataSource.getAuth(playerName); // TODO: Create method to get email only
if (auth == null) { if (auth == null) {
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE); commonService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
return; return;
} }
final String email = auth.getEmail(); final String email = auth.getEmail();
if (email == null || !email.equalsIgnoreCase(playerMail) || "your@email.com".equalsIgnoreCase(email)) { if (email == null || !email.equalsIgnoreCase(playerMail) || "your@email.com".equalsIgnoreCase(email)) {
commandService.send(player, MessageKey.INVALID_EMAIL); commonService.send(player, MessageKey.INVALID_EMAIL);
return; return;
} }
@ -84,28 +84,35 @@ public class RecoverEmailCommand extends PlayerCommand {
private void createAndSendRecoveryCode(Player player, String email) { private void createAndSendRecoveryCode(Player player, String email) {
String recoveryCode = recoveryCodeService.generateCode(player.getName()); String recoveryCode = recoveryCodeService.generateCode(player.getName());
sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode); boolean couldSendMail = sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode);
commandService.send(player, MessageKey.RECOVERY_CODE_SENT); 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) { private void processRecoveryCode(Player player, String code, String email) {
final String name = player.getName(); final String name = player.getName();
if (!recoveryCodeService.isCodeValid(name, code)) { if (recoveryCodeService.isCodeValid(name, code)) {
commandService.send(player, MessageKey.INCORRECT_RECOVERY_CODE); generateAndSendNewPassword(player, email);
return; recoveryCodeService.removeCode(name);
} else {
commonService.send(player, MessageKey.INCORRECT_RECOVERY_CODE);
} }
generateAndSendNewPassword(player, email);
recoveryCodeService.removeCode(name);
} }
private void generateAndSendNewPassword(Player player, String email) { private void generateAndSendNewPassword(Player player, String email) {
String name = player.getName(); 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); HashedPassword hashNew = passwordSecurity.computeHash(thePass, name);
dataSource.updatePassword(name, hashNew); dataSource.updatePassword(name, hashNew);
sendMailSsl.sendPasswordMail(name, email, thePass); boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, thePass);
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); if (couldSendMail) {
commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
} else {
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
}
} }
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.email; package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -14,8 +14,9 @@ import java.util.List;
* Show email command. * Show email command.
*/ */
public class ShowEmailCommand extends PlayerCommand { public class ShowEmailCommand extends PlayerCommand {
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -23,10 +24,10 @@ public class ShowEmailCommand extends PlayerCommand {
@Override @Override
public void runCommand(Player player, List<String> arguments) { public void runCommand(Player player, List<String> arguments) {
PlayerAuth auth = playerCache.getAuth(player.getName()); PlayerAuth auth = playerCache.getAuth(player.getName());
if (auth.getEmail() != null && !auth.getEmail().equalsIgnoreCase("your@email.com")) { if (auth.getEmail() != null && !"your@email.com".equalsIgnoreCase(auth.getEmail())) {
commandService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail()); commonService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail());
} else { } else {
commandService.send(player, MessageKey.SHOW_NO_EMAIL); commonService.send(player, MessageKey.SHOW_NO_EMAIL);
} }
} }
} }

View File

@ -1,15 +1,16 @@
package fr.xephi.authme.command.executable.register; package fr.xephi.authme.command.executable.register;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm; 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.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; 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.RegistrationSettings.USE_EMAIL_REGISTRATION;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION; import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION;
/**
* Command for /register.
*/
public class RegisterCommand extends PlayerCommand { public class RegisterCommand extends PlayerCommand {
@Inject @Inject
private Management management; private Management management;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private SendMailSSL sendMailSsl; private SendMailSSL sendMailSsl;
@Inject
private ValidationService validationService;
@Override @Override
public void runCommand(Player player, List<String> arguments) { public void runCommand(Player player, List<String> 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 //for two factor auth we don't need to check the usage
management.performRegister(player, "", "", true); management.performRegister(player, "", "", true);
return; return;
@ -42,11 +49,11 @@ public class RegisterCommand extends PlayerCommand {
// Ensure that there is 1 argument, or 2 if confirmation is required // Ensure that there is 1 argument, or 2 if confirmation is required
final boolean useConfirmation = isConfirmationRequired(); final boolean useConfirmation = isConfirmationRequired();
if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) { if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) {
commandService.send(player, MessageKey.USAGE_REGISTER); commonService.send(player, MessageKey.USAGE_REGISTER);
return; return;
} }
if (commandService.getProperty(USE_EMAIL_REGISTRATION)) { if (commonService.getProperty(USE_EMAIL_REGISTRATION)) {
handleEmailRegistration(player, arguments); handleEmailRegistration(player, arguments);
} else { } else {
handlePasswordRegistration(player, arguments); handlePasswordRegistration(player, arguments);
@ -59,8 +66,8 @@ public class RegisterCommand extends PlayerCommand {
} }
private void handlePasswordRegistration(Player player, List<String> arguments) { private void handlePasswordRegistration(Player player, List<String> arguments) {
if (commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) { if (commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) {
commandService.send(player, MessageKey.PASSWORD_MATCH_ERROR); commonService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
} else { } else {
management.performRegister(player, arguments.get(0), "", true); management.performRegister(player, arguments.get(0), "", true);
} }
@ -68,19 +75,19 @@ public class RegisterCommand extends PlayerCommand {
private void handleEmailRegistration(Player player, List<String> arguments) { private void handleEmailRegistration(Player player, List<String> arguments) {
if (!sendMailSsl.hasAllInformation()) { 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 " 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()); + "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
return; return;
} }
final String email = arguments.get(0); final String email = arguments.get(0);
if (!commandService.validateEmail(email)) { if (!validationService.validateEmail(email)) {
commandService.send(player, MessageKey.INVALID_EMAIL); commonService.send(player, MessageKey.INVALID_EMAIL);
} else if (commandService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) { } else if (commonService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) {
commandService.send(player, MessageKey.USAGE_REGISTER); commonService.send(player, MessageKey.USAGE_REGISTER);
} else { } 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); management.performRegister(player, thePass, email, true);
} }
} }
@ -91,8 +98,8 @@ public class RegisterCommand extends PlayerCommand {
* @return True if the confirmation is needed, false otherwise * @return True if the confirmation is needed, false otherwise
*/ */
private boolean isConfirmationRequired() { private boolean isConfirmationRequired() {
return commandService.getProperty(USE_EMAIL_REGISTRATION) return commonService.getProperty(USE_EMAIL_REGISTRATION)
? commandService.getProperty(ENABLE_CONFIRM_EMAIL) ? commonService.getProperty(ENABLE_CONFIRM_EMAIL)
: commandService.getProperty(ENABLE_PASSWORD_CONFIRMATION); : commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION);
} }
} }

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command.executable.unregister; 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.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.CommonService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -19,7 +19,7 @@ public class UnregisterCommand extends PlayerCommand {
private Management management; private Management management;
@Inject @Inject
private CommandService commandService; private CommonService commonService;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -31,7 +31,7 @@ public class UnregisterCommand extends PlayerCommand {
// Make sure the player is authenticated // Make sure the player is authenticated
if (!playerCache.isAuthenticated(playerName)) { if (!playerCache.isAuthenticated(playerName)) {
commandService.send(player, MessageKey.NOT_LOGGED_IN); commonService.send(player, MessageKey.NOT_LOGGED_IN);
return; return;
} }

View File

@ -189,7 +189,7 @@ public class PlayerAuth {
* @return String * @return String
*/ */
public String serialize() { public String serialize() {
StringBuffer str = new StringBuffer(); StringBuilder str = new StringBuilder();
char d = ';'; char d = ';';
str.append(this.nickname).append(d); str.append(this.nickname).append(d);
str.append(this.realName).append(d); str.append(this.realName).append(d);

View File

@ -84,10 +84,10 @@ public class LimboCache {
float walkSpeed = data.getWalkSpeed(); float walkSpeed = data.getWalkSpeed();
float flySpeed = data.getFlySpeed(); float flySpeed = data.getFlySpeed();
// Reset the speed value if it was 0 // Reset the speed value if it was 0
if(walkSpeed == 0f) { if(walkSpeed < 0.01f) {
walkSpeed = 0.2f; walkSpeed = 0.2f;
} }
if(flySpeed == 0f) { if(flySpeed < 0.01f) {
flySpeed = 0.2f; flySpeed = 0.2f;
} }
player.setWalkSpeed(walkSpeed); player.setWalkSpeed(walkSpeed);

View File

@ -1,6 +1,5 @@
package fr.xephi.authme.datasource; package fr.xephi.authme.datasource;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; 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.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; 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 fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -48,17 +45,12 @@ public class CacheDataSource implements DataSource {
.build(new CacheLoader<String, Optional<PlayerAuth>>() { .build(new CacheLoader<String, Optional<PlayerAuth>>() {
@Override @Override
public Optional<PlayerAuth> load(String key) { public Optional<PlayerAuth> load(String key) {
return Optional.fromNullable(source.getAuth(key)); return Optional.ofNullable(source.getAuth(key));
} }
@Override @Override
public ListenableFuture<Optional<PlayerAuth>> reload(final String key, Optional<PlayerAuth> oldValue) { public ListenableFuture<Optional<PlayerAuth>> reload(final String key, Optional<PlayerAuth> oldValue) {
return executorService.submit(new Callable<Optional<PlayerAuth>>() { return executorService.submit(() -> load(key));
@Override
public Optional<PlayerAuth> call() {
return load(key);
}
});
} }
}); });
} }
@ -90,7 +82,7 @@ public class CacheDataSource implements DataSource {
@Override @Override
public PlayerAuth getAuth(String user) { public PlayerAuth getAuth(String user) {
user = user.toLowerCase(); user = user.toLowerCase();
return cachedAuths.getUnchecked(user).orNull(); return cachedAuths.getUnchecked(user).orElse(null);
} }
@Override @Override

View File

@ -9,7 +9,6 @@ import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
@ -295,19 +294,11 @@ public class FlatFile implements DataSource {
break; break;
} }
} }
} catch (FileNotFoundException ex) {
ConsoleLogger.warning(ex.getMessage());
return false;
} catch (IOException ex) { } catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage()); ConsoleLogger.warning(ex.getMessage());
return false; return false;
} finally { } finally {
if (br != null) { silentClose(br);
try {
br.close();
} catch (IOException ignored) {
}
}
} }
if (newAuth != null) { if (newAuth != null) {
removeAuth(auth.getNickname()); removeAuth(auth.getNickname());
@ -330,19 +321,11 @@ public class FlatFile implements DataSource {
} }
} }
return countIp; return countIp;
} catch (FileNotFoundException ex) {
ConsoleLogger.warning(ex.getMessage());
return new ArrayList<>();
} catch (IOException ex) { } catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage()); ConsoleLogger.warning(ex.getMessage());
return new ArrayList<>(); return new ArrayList<>();
} finally { } finally {
if (br != null) { silentClose(br);
try {
br.close();
} catch (IOException ignored) {
}
}
} }
} }
@ -363,12 +346,7 @@ public class FlatFile implements DataSource {
} catch (IOException ex) { } catch (IOException ex) {
ConsoleLogger.warning(ex.getMessage()); ConsoleLogger.warning(ex.getMessage());
} finally { } finally {
if (br != null) { silentClose(br);
try {
br.close();
} catch (IOException ignored) {
}
}
} }
return 0; return 0;
} }

View File

@ -5,9 +5,6 @@ import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth; 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.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.XFBCRYPT; 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.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.RuntimeUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import java.sql.Blob; import java.sql.Blob;
import java.sql.Connection; import java.sql.Connection;
@ -50,7 +47,7 @@ public class MySQL implements DataSource {
private int phpBbGroup; private int phpBbGroup;
private String wordpressPrefix; private String wordpressPrefix;
public MySQL(Settings settings) throws ClassNotFoundException, SQLException, PoolInitializationException { public MySQL(Settings settings) throws ClassNotFoundException, SQLException {
setParameters(settings); setParameters(settings);
// Set the connection arguments (and check if connection is ok) // 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.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
if(poolSize == -1) { if (poolSize == -1) {
poolSize = RuntimeUtils.getCoreCount(); poolSize = Utils.getCoreCount();
} }
} }
private void setConnectionArguments() throws RuntimeException { private void setConnectionArguments() {
ds = new HikariDataSource(); ds = new HikariDataSource();
ds.setPoolName("AuthMeMYSQLPool"); ds.setPoolName("AuthMeMYSQLPool");
// Pool size // Pool size
ds.setMaximumPoolSize(poolSize); ds.setMaximumPoolSize(poolSize);
// Database URL // Database URL
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);
@ -137,7 +134,7 @@ public class MySQL implements DataSource {
} }
@Override @Override
public void reload() throws RuntimeException { public void reload() {
if (ds != null) { if (ds != null) {
ds.close(); ds.close();
} }

View File

@ -3,9 +3,6 @@ package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth; 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.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings; 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) { if (st != null) {
try { try {
st.close(); 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) { if (con != null) {
try { try {
con.close(); 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) { if (rs != null) {
try { try {
rs.close(); rs.close();
@ -479,7 +476,7 @@ public class SQLite implements DataSource {
pst.setString(1, user); pst.setString(1, user);
rs = pst.executeQuery(); rs = pst.executeQuery();
if (rs.next()) if (rs.next())
return (rs.getInt(col.IS_LOGGED) == 1); return rs.getInt(col.IS_LOGGED) == 1;
} catch (SQLException ex) { } catch (SQLException ex) {
logSqlException(ex); logSqlException(ex);
} finally { } finally {

View File

@ -43,20 +43,7 @@ public class CrazyLoginConverter implements Converter {
try (BufferedReader users = new BufferedReader(new FileReader(source))) { try (BufferedReader users = new BufferedReader(new FileReader(source))) {
while ((line = users.readLine()) != null) { while ((line = users.readLine()) != null) {
if (line.contains("|")) { if (line.contains("|")) {
String[] args = line.split("\\|"); migrateAccount(line);
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);
}
} }
} }
ConsoleLogger.info("CrazyLogin database has been imported correctly"); 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);
}
}
} }

View File

@ -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<DataSource> {
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;
}
}

View File

@ -3,6 +3,8 @@ package fr.xephi.authme.initialization;
/** /**
* Common interface for types which have data that becomes outdated * Common interface for types which have data that becomes outdated
* and that can be cleaned up periodically. * and that can be cleaned up periodically.
*
* @see fr.xephi.authme.task.CleanupTask
*/ */
public interface HasCleanup { public interface HasCleanup {

View File

@ -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));
}
}

View File

@ -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);
}
}
}

View File

@ -76,10 +76,8 @@ public class OnShutdownPlayerSaver {
dataSource.updateQuitLoc(auth); dataSource.updateQuitLoc(auth);
} }
if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN) if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
&& !settings.getProperty(RestrictionSettings.NO_TELEPORT)) { && !settings.getProperty(RestrictionSettings.NO_TELEPORT) && !limboPlayerStorage.hasData(player)) {
if (!limboPlayerStorage.hasData(player)) { limboPlayerStorage.saveData(player);
limboPlayerStorage.saveData(player);
}
} }
} }
} }

View File

@ -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));
}
}

View File

@ -2,6 +2,8 @@ package fr.xephi.authme.initialization;
/** /**
* Interface for reloadable entities. * Interface for reloadable entities.
*
* @see fr.xephi.authme.command.executable.authme.ReloadCommand
*/ */
public interface Reloadable { public interface Reloadable {

View File

@ -4,6 +4,8 @@ import fr.xephi.authme.settings.Settings;
/** /**
* Interface for classes that keep a local copy of certain settings. * Interface for classes that keep a local copy of certain settings.
*
* @see fr.xephi.authme.command.executable.authme.ReloadCommand
*/ */
public interface SettingsDependent { public interface SettingsDependent {

View File

@ -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<Settings> {
@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);
}
}

View File

@ -9,14 +9,14 @@ import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.service.AntiBotService; 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.Settings;
import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
@ -68,10 +68,10 @@ class OnJoinVerifier implements Reloadable {
* @param isAuthAvailable whether or not the player is registered * @param isAuthAvailable whether or not the player is registered
*/ */
public void checkAntibot(Player player, boolean isAuthAvailable) throws FailedVerificationException { 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; return;
} }
if (antiBotService.shouldKick(isAuthAvailable)) { if (antiBotService.shouldKick()) {
antiBotService.addPlayerKick(player.getName()); antiBotService.addPlayerKick(player.getName());
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT); throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
} }
@ -170,10 +170,9 @@ class OnJoinVerifier implements Reloadable {
public void checkPlayerCountry(boolean isAuthAvailable, public void checkPlayerCountry(boolean isAuthAvailable,
String playerIp) throws FailedVerificationException { String playerIp) throws FailedVerificationException {
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)) if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
&& settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) { && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)
if (!validationService.isCountryAdmitted(playerIp)) { && !validationService.isCountryAdmitted(playerIp)) {
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR); throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
}
} }
} }

View File

@ -6,14 +6,14 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages; import fr.xephi.authme.message.Messages;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.AntiBotService; 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.Settings;
import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; 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.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -42,6 +42,7 @@ import org.bukkit.event.player.PlayerShearEntityEvent;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; 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 class PlayerListener implements Listener {
public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>(); public static final Map<String, String> joinMessage = new ConcurrentHashMap<>();
@Inject @Inject
private Settings settings; private Settings settings;
@ -81,7 +82,7 @@ public class PlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String cmd = event.getMessage().split(" ")[0].toLowerCase(); 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; return;
} }
if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) { if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) {
@ -113,7 +114,7 @@ public class PlayerListener implements Listener {
iter.remove(); iter.remove();
} }
} }
if (recipients.size() == 0) { if (recipients.isEmpty()) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@ -156,9 +157,7 @@ public class PlayerListener implements Listener {
if (spawn != null && spawn.getWorld() != null) { if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) { if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn); player.teleport(spawn);
return; } else if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
}
if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
player.teleport(spawn); player.teleport(spawn);
} }
} }
@ -208,9 +207,11 @@ public class PlayerListener implements Listener {
final String name = player.getName(); final String name = player.getName();
if (validationService.isUnrestricted(name)) { if (validationService.isUnrestricted(name)) {
return; return;
} else if (onJoinVerifier.refusePlayerForFullServer(event)) { }
if (onJoinVerifier.refusePlayerForFullServer(event)) {
return; return;
} else if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { }
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return; return;
} }
@ -222,9 +223,9 @@ public class PlayerListener implements Listener {
// Get the auth later as this may cause the single session check to fail // Get the auth later as this may cause the single session check to fail
// Slow stuff // Slow stuff
final PlayerAuth auth = dataSource.getAuth(name); final PlayerAuth auth = dataSource.getAuth(name);
final boolean isAuthAvailable = (auth != null); final boolean isAuthAvailable = auth != null;
onJoinVerifier.checkAntibot(player, isAuthAvailable);
onJoinVerifier.checkKickNonRegistered(isAuthAvailable); onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkAntibot(player, isAuthAvailable);
onJoinVerifier.checkNameCasing(player, auth); onJoinVerifier.checkNameCasing(player, auth);
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress()); onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress());
} catch (FailedVerificationException e) { } catch (FailedVerificationException e) {
@ -233,7 +234,6 @@ public class PlayerListener implements Listener {
return; return;
} }
antiBotService.handlePlayerJoin();
teleportationService.teleportOnJoin(player); teleportationService.teleportOnJoin(player);
} }
@ -306,27 +306,14 @@ public class PlayerListener implements Listener {
* @note little hack cause InventoryOpenEvent cannot be cancelled for * @note little hack cause InventoryOpenEvent cannot be cancelled for
* real, cause no packet is send to server by client for the main inv * real, cause no packet is send to server by client for the main inv
*/ */
bukkitService.scheduleSyncDelayedTask(new Runnable() { bukkitService.scheduleSyncDelayedTask(player::closeInventory, 1);
@Override
public void run() {
player.closeInventory();
}
}, 1);
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInventoryClick(InventoryClickEvent event) { public void onPlayerInventoryClick(InventoryClickEvent event) {
if (event.getWhoClicked() == null) { if (listenerService.shouldCancelEvent(event.getWhoClicked())) {
return; 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) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)

View File

@ -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);
}
}
}

View File

@ -1,19 +1,22 @@
package fr.xephi.authme.mail; 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.ConsoleLogger;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants; import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException; import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail; import org.apache.commons.mail.HtmlEmail;
import org.bukkit.Server;
import javax.activation.CommandMap;
import javax.activation.DataSource; import javax.activation.DataSource;
import javax.activation.FileDataSource; import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.inject.Inject; import javax.inject.Inject;
import javax.mail.Session; 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 { public class SendMailSSL {
@Inject private final File dataFolder;
private AuthMe plugin; private final String serverName;
@Inject private final Settings settings;
private Settings settings;
@Inject
private BukkitService bukkitService;
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 name the name of the player
* @param mailAddress the player's email * @param mailAddress the player's email
* @param newPass the new password * @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()) { if (!hasAllInformation()) {
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete"); ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
return; return false;
} }
final String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass); HtmlEmail email;
bukkitService.runTaskAsynchronously(new Runnable() { try {
email = initializeMail(mailAddress);
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email with the given settings:", e);
return false;
}
@Override String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
public void run() { // Generate an image?
HtmlEmail email; File file = null;
try { if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
email = initializeMail(mailAddress); try {
} catch (EmailException e) { file = generateImage(name, newPass);
ConsoleLogger.logException("Failed to create email with the given settings:", e); mailText = embedImageIntoEmailContent(file, email, mailText);
return; } catch (IOException | EmailException e) {
} ConsoleLogger.logException(
"Unable to send new password as image for email " + mailAddress + ":", e);
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);
} }
}); }
boolean couldSendEmail = sendEmail(mailText, email);
FileUtils.delete(file);
return couldSendEmail;
} }
public void sendRecoveryCode(String name, String email, String code) { public boolean sendRecoveryCode(String name, String email, String code) {
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
HtmlEmail htmlEmail; HtmlEmail htmlEmail;
try { try {
htmlEmail = initializeMail(email); htmlEmail = initializeMail(email);
} catch (EmailException e) { } catch (EmailException e) {
ConsoleLogger.logException("Failed to create email for recovery code:", 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); 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); ImageIO.write(gen.generateImage(), "jpg", file);
return file; return file;
} }
@ -124,7 +123,8 @@ public class SendMailSSL {
return content.replace("<image />", "<img src=\"cid:" + tag + "\">"); return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
} }
private HtmlEmail initializeMail(String emailAddress) throws EmailException { @VisibleForTesting
HtmlEmail initializeMail(String emailAddress) throws EmailException {
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT); String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME)) String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail ? senderMail
@ -145,8 +145,18 @@ public class SendMailSSL {
return email; return email;
} }
private static boolean sendEmail(String content, HtmlEmail email) { @VisibleForTesting
boolean sendEmail(String content, HtmlEmail email) {
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader()); 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 { try {
email.setHtmlMsg(content); email.setHtmlMsg(content);
email.setTextMsg(content); email.setTextMsg(content);
@ -166,14 +176,14 @@ public class SendMailSSL {
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) { private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
return mailText return mailText
.replace("<playername />", name) .replace("<playername />", name)
.replace("<servername />", plugin.getServer().getServerName()) .replace("<servername />", serverName)
.replace("<generatedpass />", newPass); .replace("<generatedpass />", newPass);
} }
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) { private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
return mailText return mailText
.replace("<playername />", name) .replace("<playername />", name)
.replace("<servername />", plugin.getServer().getServerName()) .replace("<servername />", serverName)
.replace("<recoverycode />", code) .replace("<recoverycode />", code)
.replace("<hoursvalid />", String.valueOf(hoursValid)); .replace("<hoursvalid />", String.valueOf(hoursValid));
} }

View File

@ -53,7 +53,7 @@ public class MessageFileHandler {
if (message == null) { if (message == null) {
ConsoleLogger.warning("Error getting message with key '" + key + "'. " 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 getDefault(key);
} }
return message; return message;

View File

@ -5,156 +5,235 @@ package fr.xephi.authme.message;
*/ */
public enum MessageKey { public enum MessageKey {
/** In order to use this command you must be authenticated! */
DENIED_COMMAND("denied_command"), DENIED_COMMAND("denied_command"),
/** A player with the same IP is already in game! */
SAME_IP_ONLINE("same_ip_online"), SAME_IP_ONLINE("same_ip_online"),
/** In order to chat you must be authenticated! */
DENIED_CHAT("denied_chat"), DENIED_CHAT("denied_chat"),
/** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */
KICK_ANTIBOT("kick_antibot"), KICK_ANTIBOT("kick_antibot"),
/** Can't find the requested user in the database! */
UNKNOWN_USER("unknown_user"), UNKNOWN_USER("unknown_user"),
/** Your quit location was unsafe, you have been teleported to the world's spawnpoint. */
UNSAFE_QUIT_LOCATION("unsafe_spawn"), UNSAFE_QUIT_LOCATION("unsafe_spawn"),
/** You're not logged in! */
NOT_LOGGED_IN("not_logged_in"), NOT_LOGGED_IN("not_logged_in"),
/** You can register yourself to the server with the command "/register &gt;password> &gt;ConfirmPassword>" */
REGISTER_VOLUNTARILY("reg_voluntarily"), REGISTER_VOLUNTARILY("reg_voluntarily"),
/** Usage: /login &gt;password> */
USAGE_LOGIN("usage_log"), USAGE_LOGIN("usage_log"),
/** Wrong password! */
WRONG_PASSWORD("wrong_pwd"), WRONG_PASSWORD("wrong_pwd"),
/** Successfully unregistered! */
UNREGISTERED_SUCCESS("unregistered"), UNREGISTERED_SUCCESS("unregistered"),
/** In-game registration is disabled! */
REGISTRATION_DISABLED("reg_disabled"), REGISTRATION_DISABLED("reg_disabled"),
/** Logged-in due to Session Reconnection. */
SESSION_RECONNECTION("valid_session"), SESSION_RECONNECTION("valid_session"),
/** Successful login! */
LOGIN_SUCCESS("login"), LOGIN_SUCCESS("login"),
/** Your account isn't activated yet, please check your emails! */
ACCOUNT_NOT_ACTIVATED("vb_nonActiv"), ACCOUNT_NOT_ACTIVATED("vb_nonActiv"),
/** You already have registered this username! */
NAME_ALREADY_REGISTERED("user_regged"), NAME_ALREADY_REGISTERED("user_regged"),
/** You don't have the permission to perform this action! */
NO_PERMISSION("no_perm"), NO_PERMISSION("no_perm"),
/** An unexpected error occurred, please contact an administrator! */
ERROR("error"), ERROR("error"),
/** Please, login with the command "/login &gt;password>" */
LOGIN_MESSAGE("login_msg"), LOGIN_MESSAGE("login_msg"),
/** Please, register to the server with the command "/register &gt;password> &gt;ConfirmPassword>" */
REGISTER_MESSAGE("reg_msg"), REGISTER_MESSAGE("reg_msg"),
/** Please, register to the server with the command "/register &gt;email> &gt;confirmEmail>" */
REGISTER_EMAIL_MESSAGE("reg_email_msg"), 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"), MAX_REGISTER_EXCEEDED("max_reg", "%max_acc", "%reg_count", "%reg_names"),
/** Usage: /register &gt;password> &gt;ConfirmPassword> */
USAGE_REGISTER("usage_reg"), USAGE_REGISTER("usage_reg"),
/** Usage: /unregister &gt;password> */
USAGE_UNREGISTER("usage_unreg"), USAGE_UNREGISTER("usage_unreg"),
/** Password changed successfully! */
PASSWORD_CHANGED_SUCCESS("pwd_changed"), PASSWORD_CHANGED_SUCCESS("pwd_changed"),
/** This user isn't registered! */
USER_NOT_REGISTERED("user_unknown"), USER_NOT_REGISTERED("user_unknown"),
/** Passwords didn't match, check them again! */
PASSWORD_MATCH_ERROR("password_error"), PASSWORD_MATCH_ERROR("password_error"),
/** You can't use your name as password, please choose another one... */
PASSWORD_IS_USERNAME_ERROR("password_error_nick"), PASSWORD_IS_USERNAME_ERROR("password_error_nick"),
/** The chosen password isn't safe, please choose another one... */
PASSWORD_UNSAFE_ERROR("password_error_unsafe"), PASSWORD_UNSAFE_ERROR("password_error_unsafe"),
/** Your password contains illegal characters. Allowed chars: REG_EX */
PASSWORD_CHARACTERS_ERROR("password_error_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"), SESSION_EXPIRED("invalid_session"),
/** Only registered users can join the server! Please visit http://example.com to register yourself! */
MUST_REGISTER_MESSAGE("reg_only"), MUST_REGISTER_MESSAGE("reg_only"),
/** You're already logged in! */
ALREADY_LOGGED_IN_ERROR("logged_in"), ALREADY_LOGGED_IN_ERROR("logged_in"),
/** Logged-out successfully! */
LOGOUT_SUCCESS("logout"), LOGOUT_SUCCESS("logout"),
/** The same username is already playing on the server! */
USERNAME_ALREADY_ONLINE_ERROR("same_nick"), USERNAME_ALREADY_ONLINE_ERROR("same_nick"),
/** Successfully registered! */
REGISTER_SUCCESS("registered"), REGISTER_SUCCESS("registered"),
/** Your password is too short or too long! Please try with another one! */
INVALID_PASSWORD_LENGTH("pass_len"), INVALID_PASSWORD_LENGTH("pass_len"),
/** Configuration and database have been reloaded correctly! */
CONFIG_RELOAD_SUCCESS("reload"), CONFIG_RELOAD_SUCCESS("reload"),
/** Login timeout exceeded, you have been kicked from the server, please try again! */
LOGIN_TIMEOUT_ERROR("timeout"), LOGIN_TIMEOUT_ERROR("timeout"),
/** Usage: /changepassword &gt;oldPassword> &gt;newPassword> */
USAGE_CHANGE_PASSWORD("usage_changepassword"), USAGE_CHANGE_PASSWORD("usage_changepassword"),
/** Your username is either too short or too long! */
INVALID_NAME_LENGTH("name_len"), INVALID_NAME_LENGTH("name_len"),
/** Your username contains illegal characters. Allowed chars: REG_EX */
INVALID_NAME_CHARACTERS("regex", "REG_EX"), INVALID_NAME_CHARACTERS("regex", "REG_EX"),
/** Please add your email to your account with the command "/email add &gt;yourEmail> &gt;confirmEmail>" */
ADD_EMAIL_MESSAGE("add_email"), ADD_EMAIL_MESSAGE("add_email"),
/** Forgot your password? Please use the command "/email recovery &gt;yourEmail>" */
FORGOT_PASSWORD_MESSAGE("recovery_email"), FORGOT_PASSWORD_MESSAGE("recovery_email"),
/** To login you have to solve a captcha code, please use the command "/captcha &gt;theCaptcha>" */
USAGE_CAPTCHA("usage_captcha", "<theCaptcha>"), USAGE_CAPTCHA("usage_captcha", "<theCaptcha>"),
/** Wrong captcha, please type "/captcha THE_CAPTCHA" into the chat! */
CAPTCHA_WRONG_ERROR("wrong_captcha", "THE_CAPTCHA"), CAPTCHA_WRONG_ERROR("wrong_captcha", "THE_CAPTCHA"),
/** Captcha code solved correctly! */
CAPTCHA_SUCCESS("valid_captcha"), CAPTCHA_SUCCESS("valid_captcha"),
/** A VIP player has joined the server when it was full! */
KICK_FOR_VIP("kick_forvip"), KICK_FOR_VIP("kick_forvip"),
/** The server is full, try again later! */
KICK_FULL_SERVER("kick_fullserver"), KICK_FULL_SERVER("kick_fullserver"),
/** Usage: /email add &gt;email> &gt;confirmEmail> */
USAGE_ADD_EMAIL("usage_email_add"), USAGE_ADD_EMAIL("usage_email_add"),
/** Usage: /email change &gt;oldEmail> &gt;newEmail> */
USAGE_CHANGE_EMAIL("usage_email_change"), USAGE_CHANGE_EMAIL("usage_email_change"),
/** Usage: /email recovery &gt;Email> */
USAGE_RECOVER_EMAIL("usage_email_recovery"), USAGE_RECOVER_EMAIL("usage_email_recovery"),
/** Invalid new email, try again! */
INVALID_NEW_EMAIL("new_email_invalid"), INVALID_NEW_EMAIL("new_email_invalid"),
/** Invalid old email, try again! */
INVALID_OLD_EMAIL("old_email_invalid"), INVALID_OLD_EMAIL("old_email_invalid"),
/** Invalid email address, try again! */
INVALID_EMAIL("email_invalid"), INVALID_EMAIL("email_invalid"),
/** Email address successfully added to your account! */
EMAIL_ADDED_SUCCESS("email_added"), EMAIL_ADDED_SUCCESS("email_added"),
/** Please confirm your email address! */
CONFIRM_EMAIL_MESSAGE("email_confirm"), CONFIRM_EMAIL_MESSAGE("email_confirm"),
/** Email address changed correctly! */
EMAIL_CHANGED_SUCCESS("email_changed"), EMAIL_CHANGED_SUCCESS("email_changed"),
/** Your current email address is: %email */
EMAIL_SHOW("email_show", "%email"), EMAIL_SHOW("email_show", "%email"),
/** You currently don't have email address associated with this account. */
SHOW_NO_EMAIL("show_no_email"), SHOW_NO_EMAIL("show_no_email"),
/** Recovery email sent successfully! Please check your email inbox! */
RECOVERY_EMAIL_SENT_MESSAGE("email_send"), 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"), RECOVERY_EMAIL_ALREADY_SENT_MESSAGE("email_exists"),
/** Your country is banned from this server! */
COUNTRY_BANNED_ERROR("country_banned"), COUNTRY_BANNED_ERROR("country_banned"),
/** [AntiBotService] AntiBot enabled due to the huge number of connections! */
ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"), ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"),
/** [AntiBotService] AntiBot disabled after %m minutes! */
ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"), ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"),
/** The email address is already being used */
EMAIL_ALREADY_USED_ERROR("email_already_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"), 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"), NOT_OWNER_ERROR("not_owner_error"),
/** You should join using username %valid, not %invalid. */
INVALID_NAME_CASE("invalid_name_case", "%valid", "%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"), TEMPBAN_MAX_LOGINS("tempban_max_logins"),
/** You own %count accounts: */
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"), ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
/** The player %name has %count accounts: */
ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"), ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"),
/** An admin just registered you; please log in again */
KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"), 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"), 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"), 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"); INCORRECT_RECOVERY_CODE("recovery_code_incorrect");
private String key; private String key;

View File

@ -12,14 +12,9 @@ import org.apache.logging.log4j.message.Message;
* *
* @author Xephi59 * @author Xephi59
*/ */
@SuppressWarnings("serial")
public class Log4JFilter extends AbstractFilter { public class Log4JFilter extends AbstractFilter {
/** private static final long serialVersionUID = -5594073755007974254L;
* Constructor.
*/
public Log4JFilter() {
}
/** /**
* Validates a Message instance and returns the {@link Result} value * Validates a Message instance and returns the {@link Result} value

View File

@ -10,6 +10,7 @@ import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Arrays; import java.util.Arrays;
@ -31,7 +32,8 @@ public class AuthGroupHandler implements Reloadable {
private String unregisteredGroup; private String unregisteredGroup;
private String registeredGroup; private String registeredGroup;
AuthGroupHandler() { } AuthGroupHandler() {
}
/** /**
* Set the group of a player, by its AuthMe group type. * Set the group of a player, by its AuthMe group type.
@ -114,6 +116,7 @@ public class AuthGroupHandler implements Reloadable {
} }
@Override @Override
@PostConstruct
public void reload() { public void reload() {
unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP); unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP); unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);

View File

@ -78,12 +78,12 @@ public class PermissionsManager implements Reloadable {
if (handler != null) { if (handler != null) {
// Show a success message and return // Show a success message and return
this.handler = handler; this.handler = handler;
ConsoleLogger.info("Hooked into " + type.getName() + "!"); ConsoleLogger.info("Hooked into " + type.getDisplayName() + "!");
return; return;
} }
} catch (Exception ex) { } catch (Exception ex) {
// An error occurred, show a warning message // 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 // Make sure the plugin is enabled before hooking
if (!plugin.isEnabled()) { 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; return null;
} }
@ -414,7 +414,7 @@ public class PermissionsManager implements Reloadable {
*/ */
public boolean setGroups(Player player, List<String> groupNames) { public boolean setGroups(Player player, List<String> groupNames) {
// If no permissions system is used or if there's no group supplied, return false // 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; return false;
// Set the main group // Set the main group

View File

@ -33,21 +33,21 @@ public enum PermissionsSystemType {
/** /**
* The display name of the permissions system. * The display name of the permissions system.
*/ */
public String name; private String displayName;
/** /**
* The name of the permissions system plugin. * The name of the permissions system plugin.
*/ */
public String pluginName; private String pluginName;
/** /**
* Constructor for PermissionsSystemType. * 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. * @param pluginName Name of the plugin.
*/ */
PermissionsSystemType(String name, String pluginName) { PermissionsSystemType(String displayName, String pluginName) {
this.name = name; this.displayName = displayName;
this.pluginName = pluginName; this.pluginName = pluginName;
} }
@ -56,8 +56,8 @@ public enum PermissionsSystemType {
* *
* @return Display name. * @return Display name.
*/ */
public String getName() { public String getDisplayName() {
return this.name; return this.displayName;
} }
/** /**
@ -76,7 +76,7 @@ public enum PermissionsSystemType {
*/ */
@Override @Override
public String toString() { public String toString() {
return getName(); return getDisplayName();
} }
/** /**

View File

@ -17,7 +17,7 @@ public enum PlayerStatePermission implements PermissionNode {
BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY), 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), IS_VIP("authme.vip", DefaultPermission.OP_ONLY),

View File

@ -55,7 +55,7 @@ public class BPermissionsHandler implements PermissionHandler {
List<String> groups = getGroups(player); List<String> groups = getGroups(player);
// Make sure there is any group available, or return null // Make sure there is any group available, or return null
if (groups.size() == 0) if (groups.isEmpty())
return null; return null;
// Return the first group // Return the first group

View File

@ -54,7 +54,7 @@ public class PermissionsBukkitHandler implements PermissionHandler {
List<String> groups = getGroups(player); List<String> groups = getGroups(player);
// Make sure there is any group available, or return null // Make sure there is any group available, or return null
if (groups.size() == 0) if (groups.isEmpty())
return null; return null;
// Return the first group // Return the first group

View File

@ -77,7 +77,7 @@ public class PermissionsExHandler implements PermissionHandler {
PermissionUser user = permissionManager.getUser(player); PermissionUser user = permissionManager.getUser(player);
List<String> groups = user.getParentIdentifiers(null); List<String> groups = user.getParentIdentifiers(null);
if (groups.size() == 0) if (groups.isEmpty())
return null; return null;
return groups.get(0); return groups.get(0);

View File

@ -6,7 +6,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess; 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.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -19,7 +19,7 @@ public class AsyncChangePassword implements AsynchronousProcess {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private ProcessService processService; private CommonService commonService;
@Inject @Inject
private PasswordSecurity passwordSecurity; private PasswordSecurity passwordSecurity;
@ -27,7 +27,8 @@ public class AsyncChangePassword implements AsynchronousProcess {
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
AsyncChangePassword() { } AsyncChangePassword() {
}
public void changePassword(final Player player, String oldPassword, String newPassword) { public void changePassword(final Player player, String oldPassword, String newPassword) {
@ -38,15 +39,15 @@ public class AsyncChangePassword implements AsynchronousProcess {
auth.setPassword(hashedPassword); auth.setPassword(hashedPassword);
if (!dataSource.updatePassword(auth)) { if (!dataSource.updatePassword(auth)) {
processService.send(player, MessageKey.ERROR); commonService.send(player, MessageKey.ERROR);
return; return;
} }
playerCache.updatePlayer(auth); playerCache.updatePlayer(auth);
processService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS); commonService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password"); ConsoleLogger.info(player.getName() + " changed his password");
} else { } else {
processService.send(player, MessageKey.WRONG_PASSWORD); commonService.send(player, MessageKey.WRONG_PASSWORD);
} }
} }
} }

View File

@ -6,7 +6,8 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess; 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 fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -18,7 +19,7 @@ import javax.inject.Inject;
public class AsyncAddEmail implements AsynchronousProcess { public class AsyncAddEmail implements AsynchronousProcess {
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@ -26,6 +27,9 @@ public class AsyncAddEmail implements AsynchronousProcess {
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@Inject
private ValidationService validationService;
AsyncAddEmail() { } AsyncAddEmail() { }
public void addEmail(Player player, String email) { public void addEmail(Player player, String email) {
@ -37,9 +41,9 @@ public class AsyncAddEmail implements AsynchronousProcess {
if (currentEmail != null && !"your@email.com".equals(currentEmail)) { if (currentEmail != null && !"your@email.com".equals(currentEmail)) {
service.send(player, MessageKey.USAGE_CHANGE_EMAIL); service.send(player, MessageKey.USAGE_CHANGE_EMAIL);
} else if (!service.validateEmail(email)) { } else if (!validationService.validateEmail(email)) {
service.send(player, MessageKey.INVALID_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); service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else { } else {
auth.setEmail(email); auth.setEmail(email);

View File

@ -5,7 +5,8 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess; 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 fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -17,7 +18,7 @@ import javax.inject.Inject;
public class AsyncChangeEmail implements AsynchronousProcess { public class AsyncChangeEmail implements AsynchronousProcess {
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -25,6 +26,9 @@ public class AsyncChangeEmail implements AsynchronousProcess {
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@Inject
private ValidationService validationService;
AsyncChangeEmail() { } AsyncChangeEmail() { }
public void changeEmail(Player player, String oldEmail, String newEmail) { public void changeEmail(Player player, String oldEmail, String newEmail) {
@ -35,11 +39,11 @@ public class AsyncChangeEmail implements AsynchronousProcess {
if (currentEmail == null) { if (currentEmail == null) {
service.send(player, MessageKey.USAGE_ADD_EMAIL); 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); service.send(player, MessageKey.INVALID_NEW_EMAIL);
} else if (!oldEmail.equals(currentEmail)) { } else if (!oldEmail.equals(currentEmail)) {
service.send(player, MessageKey.INVALID_OLD_EMAIL); 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); service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else { } else {
saveNewEmail(auth, player, newEmail); saveNewEmail(auth, player, newEmail);

View File

@ -13,8 +13,9 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess; 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.process.login.AsynchronousLogin;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; 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.task.LimboPlayerTaskManager;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.PlayerUtils; import fr.xephi.authme.util.PlayerUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
@ -39,9 +38,6 @@ import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
*/ */
public class AsynchronousJoin implements AsynchronousProcess { public class AsynchronousJoin implements AsynchronousProcess {
private static final boolean DISABLE_COLLISIONS = MethodUtils
.getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null;
@Inject @Inject
private AuthMe plugin; private AuthMe plugin;
@ -49,7 +45,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
private DataSource database; private DataSource database;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;
@ -72,23 +68,20 @@ public class AsynchronousJoin implements AsynchronousProcess {
@Inject @Inject
private AsynchronousLogin asynchronousLogin; private AsynchronousLogin asynchronousLogin;
@Inject
private CommandManager commandManager;
AsynchronousJoin() { AsynchronousJoin() {
} }
public void processJoin(final Player player) { public void processJoin(final Player player) {
final String name = player.getName().toLowerCase(); final String name = player.getName().toLowerCase();
final String ip = PlayerUtils.getPlayerIp(player); final String ip = PlayerUtils.getPlayerIp(player);
if (isPlayerUnrestricted(name)) { if (service.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name)) {
return; return;
} }
// Prevent player collisions in 1.9
if (DISABLE_COLLISIONS) {
player.setCollidable(false);
}
if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE) if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE)
&& !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) { && !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) {
bukkitService.runTask(() -> player.setGameMode(GameMode.SURVIVAL)); bukkitService.runTask(() -> player.setGameMode(GameMode.SURVIVAL));
@ -115,7 +108,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
return; return;
} }
final boolean isAuthAvailable = database.isAuthAvailable(name); final boolean isAuthAvailable = database.isAuthAvailable(name);
if (isAuthAvailable) { if (isAuthAvailable) {
@ -162,26 +154,23 @@ public class AsynchronousJoin implements AsynchronousProcess {
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND; final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() { bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
@Override player.setOp(false);
public void run() { if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
player.setOp(false); && service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT) player.setFlySpeed(0.0f);
&& service.getProperty(RestrictionSettings.REMOVE_SPEED)) { player.setWalkSpeed(0.0f);
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));
}
} }
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 // Timeout and message task
@ -189,10 +178,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
limboPlayerTaskManager.registerMessageTask(name, isAuthAvailable); 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. * Returns whether the name is restricted based on the restriction settings.
* *

View File

@ -16,7 +16,7 @@ import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess; 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.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.DatabaseSettings;
@ -44,7 +44,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PermissionsManager permissionsManager; private PermissionsManager permissionsManager;
@ -224,7 +224,11 @@ public class AsynchronousLogin implements AsynchronousProcess {
player.setNoDamageTicks(0); player.setNoDamageTicks(0);
service.send(player, MessageKey.LOGIN_SUCCESS); service.send(player, MessageKey.LOGIN_SUCCESS);
displayOtherAccounts(auth, player);
// Other auths
List<String> auths = dataSource.getAllAuthsByIp(auth.getIp());
runCommandOtherAccounts(auths, player, auth.getIp());
displayOtherAccounts(auths, player);
final String email = auth.getEmail(); final String email = auth.getEmail();
if (service.getProperty(EmailSettings.RECALL_PLAYERS) if (service.getProperty(EmailSettings.RECALL_PLAYERS)
@ -252,12 +256,29 @@ public class AsynchronousLogin implements AsynchronousProcess {
} }
} }
private void displayOtherAccounts(PlayerAuth auth, Player player) { private void runCommandOtherAccounts(List<String> auths, Player player, String ip) {
if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auth == null) { 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<String> auths, Player player) {
if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS)) {
return; return;
} }
List<String> auths = dataSource.getAllAuthsByIp(auth.getIp());
if (auths.size() <= 1) { if (auths.size() <= 1) {
return; return;
} }

View File

@ -8,38 +8,31 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.LoginEvent; import fr.xephi.authme.events.LoginEvent;
import fr.xephi.authme.events.RestoreInventoryEvent; import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.listener.PlayerListener; import fr.xephi.authme.listener.PlayerListener;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.process.SynchronousProcess; 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.BukkitService;
import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.service.TeleportationService; 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.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject; 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; import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
public class ProcessSyncPlayerLogin implements SynchronousProcess { public class ProcessSyncPlayerLogin implements SynchronousProcess {
private static final boolean RESTORE_COLLISIONS = MethodUtils
.getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null;
@Inject @Inject
private AuthMe plugin; private AuthMe plugin;
@Inject @Inject
private BungeeService bungeeService; private BungeeService bungeeService;
@Inject
private ProcessService service;
@Inject @Inject
private LimboCache limboCache; private LimboCache limboCache;
@ -55,6 +48,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@Inject
private CommandManager commandManager;
@Inject
private Settings settings;
ProcessSyncPlayerLogin() { 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) { public void processPlayerLogin(Player player) {
final String name = player.getName().toLowerCase(); final String name = player.getName().toLowerCase();
@ -88,11 +77,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// because LimboCache#restoreData teleport player to last location. // because LimboCache#restoreData teleport player to last location.
} }
if (RESTORE_COLLISIONS && !service.getProperty(KEEP_COLLISIONS_DISABLED)) { if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
player.setCollidable(true);
}
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
restoreInventory(player); restoreInventory(player);
} }
@ -100,19 +85,16 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
teleportationService.teleportOnLogin(player, auth, limbo); teleportationService.teleportOnLogin(player, auth, limbo);
// We can now display the join message (if delayed) // We can now display the join message (if delayed)
String jm = PlayerListener.joinMessage.get(name); String joinMessage = PlayerListener.joinMessage.remove(name);
if (jm != null) { if (!StringUtils.isEmpty(joinMessage)) {
if (!jm.isEmpty()) { for (Player p : bukkitService.getOnlinePlayers()) {
for (Player p : bukkitService.getOnlinePlayers()) { if (p.isOnline()) {
if (p.isOnline()) { p.sendMessage(joinMessage);
p.sendMessage(jm);
}
} }
} }
PlayerListener.joinMessage.remove(name);
} }
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
player.removePotionEffect(PotionEffectType.BLINDNESS); player.removePotionEffect(PotionEffectType.BLINDNESS);
} }
@ -121,20 +103,20 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
player.saveData(); player.saveData();
// Login is done, display welcome message // Login is done, display welcome message
if (service.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
if (service.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) { if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
for (String s : service.getSettings().getWelcomeMessage()) { for (String s : settings.getWelcomeMessage()) {
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
} }
} else { } else {
for (String s : service.getSettings().getWelcomeMessage()) { for (String s : settings.getWelcomeMessage()) {
player.sendMessage(plugin.replaceAllInfo(s, player)); player.sendMessage(plugin.replaceAllInfo(s, player));
} }
} }
} }
// Login is now finished; we can force all commands // 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. // Send Bungee stuff. The service will check if it is enabled or not.
bungeeService.connectPlayer(player); bungeeService.connectPlayer(player);

View File

@ -6,7 +6,7 @@ import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess; 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.SyncProcessManager;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -19,7 +19,7 @@ public class AsynchronousLogout implements AsynchronousProcess {
private DataSource database; private DataSource database;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;

View File

@ -6,7 +6,7 @@ import fr.xephi.authme.events.LogoutEvent;
import fr.xephi.authme.listener.protocollib.ProtocolLibService; import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType; 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.process.SynchronousProcess;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; 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 { public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private BukkitService bukkitService; private BukkitService bukkitService;

View File

@ -7,7 +7,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.process.AsynchronousProcess; 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.SyncProcessManager;
import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
@ -27,7 +27,7 @@ public class AsynchronousQuit implements AsynchronousProcess {
private DataSource database; private DataSource database;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PlayerCache playerCache; private PlayerCache playerCache;

View File

@ -7,7 +7,7 @@ import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.AsynchronousProcess; 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.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin; import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
@ -51,7 +51,7 @@ public class AsyncRegister implements AsynchronousProcess {
@Inject @Inject
private PasswordSecurity passwordSecurity; private PasswordSecurity passwordSecurity;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private SyncProcessManager syncProcessManager; private SyncProcessManager syncProcessManager;
@Inject @Inject
@ -148,8 +148,12 @@ public class AsyncRegister implements AsynchronousProcess {
} }
database.updateEmail(auth); database.updateEmail(auth);
database.updateSession(auth); database.updateSession(auth);
sendMailSsl.sendPasswordMail(name, email, password); boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, password);
syncProcessManager.processSyncEmailRegister(player); if (couldSendMail) {
syncProcessManager.processSyncEmailRegister(player);
} else {
service.send(player, MessageKey.EMAIL_SEND_FAILURE);
}
} }
private void passwordRegister(final Player player, String password, boolean autoLogin) { private void passwordRegister(final Player player, String password, boolean autoLogin) {

View File

@ -3,7 +3,7 @@ package fr.xephi.authme.process.register;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType; 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.process.SynchronousProcess;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager; import fr.xephi.authme.task.LimboPlayerTaskManager;
@ -16,13 +16,13 @@ import javax.inject.Inject;
public class ProcessSyncEmailRegister implements SynchronousProcess { public class ProcessSyncEmailRegister implements SynchronousProcess {
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private LimboPlayerTaskManager limboPlayerTaskManager; private LimboPlayerTaskManager limboPlayerTaskManager;
ProcessSyncEmailRegister() { } ProcessSyncEmailRegister() {
}
public void processEmailRegister(Player player) { public void processEmailRegister(Player player) {
final String name = player.getName().toLowerCase(); final String name = player.getName().toLowerCase();

View File

@ -4,15 +4,15 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboCache; import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType; 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.process.SynchronousProcess;
import fr.xephi.authme.service.BungeeService; 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.EmailSettings;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager; import fr.xephi.authme.task.LimboPlayerTaskManager;
import fr.xephi.authme.util.PlayerUtils; import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -25,7 +25,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
private BungeeService bungeeService; private BungeeService bungeeService;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private LimboCache limboCache; private LimboCache limboCache;
@ -33,17 +33,10 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
@Inject @Inject
private LimboPlayerTaskManager limboPlayerTaskManager; private LimboPlayerTaskManager limboPlayerTaskManager;
ProcessSyncPasswordRegister() { @Inject
} private CommandManager commandManager;
private void forceCommands(Player player) { ProcessSyncPasswordRegister() {
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()));
}
} }
/** /**
@ -83,7 +76,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
} }
// Register is now finished; we can force all commands // Register is now finished; we can force all commands
forceCommands(player); commandManager.runCommandsOnRegister(player);
// Request login after registration // Request login after registration
if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) { if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) {

View File

@ -9,7 +9,7 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupHandler; import fr.xephi.authme.permission.AuthGroupHandler;
import fr.xephi.authme.permission.AuthGroupType; import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.AsynchronousProcess; 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.PasswordSecurity;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
@ -31,7 +31,7 @@ public class AsynchronousUnregister implements AsynchronousProcess {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private ProcessService service; private CommonService service;
@Inject @Inject
private PasswordSecurity passwordSecurity; private PasswordSecurity passwordSecurity;

View File

@ -3,8 +3,7 @@ package fr.xephi.authme.security;
import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.EncryptionMethod;
/** /**
* The list of hash algorithms supported by AuthMe. The linked {@link EncryptionMethod} implementation * Hash algorithms supported by AuthMe.
* must be able to be instantiated with the default constructor.
*/ */
public enum HashAlgorithm { public enum HashAlgorithm {
@ -18,8 +17,8 @@ public enum HashAlgorithm {
MD5(fr.xephi.authme.security.crypts.MD5.class), MD5(fr.xephi.authme.security.crypts.MD5.class),
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class), MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
MYBB(fr.xephi.authme.security.crypts.MYBB.class), MYBB(fr.xephi.authme.security.crypts.MYBB.class),
PBKDF2(fr.xephi.authme.security.crypts.CryptPBKDF2.class), PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
PBKDF2DJANGO(fr.xephi.authme.security.crypts.CryptPBKDF2Django.class), PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class), PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class), PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
@Deprecated @Deprecated

View File

@ -6,12 +6,14 @@ import fr.xephi.authme.events.PasswordEncryptionEvent;
import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.EnumSetProperty;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Collection;
/** /**
* Manager class for password-related operations. * Manager class for password-related operations.
@ -31,7 +33,7 @@ public class PasswordSecurity implements Reloadable {
private Injector injector; private Injector injector;
private HashAlgorithm algorithm; private HashAlgorithm algorithm;
private boolean supportOldAlgorithm; private Collection<HashAlgorithm> legacyAlgorithms;
/** /**
* Load or reload the configuration. * Load or reload the configuration.
@ -40,7 +42,8 @@ public class PasswordSecurity implements Reloadable {
@Override @Override
public void reload() { public void reload() {
this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); 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<HashAlgorithm>) SecuritySettings.LEGACY_HASHES).asEnumSet(settings);
} }
/** /**
@ -83,7 +86,7 @@ public class PasswordSecurity implements Reloadable {
EncryptionMethod method = initializeEncryptionMethodWithEvent(algorithm, playerName); EncryptionMethod method = initializeEncryptionMethodWithEvent(algorithm, playerName);
String playerLowerCase = playerName.toLowerCase(); String playerLowerCase = playerName.toLowerCase();
return methodMatches(method, password, hashedPassword, playerLowerCase) 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 * @return True if there was a password match with another encryption method, false otherwise
*/ */
private boolean compareWithAllEncryptionMethods(String password, HashedPassword hashedPassword, String playerName) { private boolean compareWithLegacyHashes(String password, HashedPassword hashedPassword, String playerName) {
for (HashAlgorithm algorithm : HashAlgorithm.values()) { for (HashAlgorithm algorithm : legacyAlgorithms) {
if (!HashAlgorithm.CUSTOM.equals(algorithm)) { EncryptionMethod method = initializeEncryptionMethod(algorithm);
EncryptionMethod method = initializeEncryptionMethod(algorithm); if (methodMatches(method, password, hashedPassword, playerName)) {
if (methodMatches(method, password, hashedPassword, playerName)) { hashPasswordForNewAlgorithm(password, playerName);
hashPasswordForNewAlgorithm(password, playerName); return true;
return true;
}
} }
} }
return false; return false;

View File

@ -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;
}
}

View File

@ -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.Recommendation;
import fr.xephi.authme.security.crypts.description.Usage; import fr.xephi.authme.security.crypts.description.Usage;
@Recommendation(Usage.RECOMMENDED) @Recommendation(Usage.ACCEPTABLE)
public class JOOMLA extends HexSaltedMethod { public class JOOMLA extends HexSaltedMethod {
@Override @Override

View File

@ -1,5 +1,10 @@
package fr.xephi.authme.security.crypts; package fr.xephi.authme.security.crypts;
/**
* Plaintext password storage.
*
* @deprecated Using this is no longer supported. AuthMe will migrate to SHA256 on startup.
*/
@Deprecated @Deprecated
public class PLAINTEXT extends UnsaltedMethod { public class PLAINTEXT extends UnsaltedMethod {

View File

@ -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;
}
}

View File

@ -1,15 +1,14 @@
package fr.xephi.authme.security.crypts; 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.ConsoleLogger;
import fr.xephi.authme.security.crypts.description.AsciiRestricted; 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; import javax.xml.bind.DatatypeConverter;
@AsciiRestricted @AsciiRestricted
public class CryptPBKDF2Django extends HexSaltedMethod { public class Pbkdf2Django extends HexSaltedMethod {
private static final int DEFAULT_ITERATIONS = 24000; 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); PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), DEFAULT_ITERATIONS);
PBKDF2Engine engine = new PBKDF2Engine(params); PBKDF2Engine engine = new PBKDF2Engine(params);
return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32))); return result + DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32));
} }
@Override @Override
@ -32,8 +31,7 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
try { try {
iterations = Integer.parseInt(line[1]); iterations = Integer.parseInt(line[1]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
ConsoleLogger.warning("Could not read number of rounds for CryptPBKDF2Django:" ConsoleLogger.logException("Could not read number of rounds for Pbkdf2Django:", e);
+ StringUtils.formatException(e));
return false; return false;
} }
String salt = line[2]; String salt = line[2];

View File

@ -18,14 +18,14 @@ public class XAUTH extends HexSaltedMethod {
@Override @Override
public String computeHash(String password, String salt, String name) { public String computeHash(String password, String salt, String name) {
String hash = getWhirlpool(salt + password).toLowerCase(); 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); return hash.substring(0, saltPos) + salt + hash.substring(saltPos);
} }
@Override @Override
public boolean comparePassword(String password, HashedPassword hashedPassword, String playerName) { public boolean comparePassword(String password, HashedPassword hashedPassword, String playerName) {
String hash = hashedPassword.getHash(); 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()) { if (saltPos + 12 > hash.length()) {
return false; return false;
} }

View File

@ -1,114 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/*
* Free auxiliary functions. Copyright 2007, 2014, Matthias G&auml;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&auml;rtner
*/
public class BinTools {
public static final String hex = "0123456789ABCDEF";
/**
* Simple binary-to-hexadecimal conversion.
*
* @param b
* Input bytes. May be <code>null</code>.
* @return Hexadecimal representation of b. Uppercase A-F, two characters
* per byte. Empty string on <code>null</code> 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 <code>null</code>
* . On odd length leading zero will be assumed.
* @return Array on bytes, non-<code>null</code>.
* @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");
}
}
}

View File

@ -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;
/**
* <p>
* Default PRF implementation based on standard javax.crypt.Mac mechanisms.
* </p>
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;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);
}
}
}

View File

@ -1,97 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/**
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;rtner
* @version 1.0
*/
public interface PBKDF2 {
/**
* Convert String-based input to internal byte array, then invoke PBKDF2.
* Desired key length defaults to Pseudo Random Function block size.
*
* @param inputPassword Candidate password to compute the derived key for.
*
* @return internal byte array
*/
byte[] deriveKey(String inputPassword);
/**
* Convert String-based input to internal byte array, then invoke PBKDF2.
*
* @param inputPassword Candidate password to compute the derived key for.
* @param dkLen Specify desired key length
*
* @return internal byte array
*/
byte[] deriveKey(String inputPassword, int dkLen);
/**
* Convert String-based input to internal byte arrays, then invoke PBKDF2
* and verify result against the reference data that is supplied in the
* PBKDF2Parameters.
*
* @param inputPassword Candidate password to compute the derived key for.
*
* @return <code>true</code> password match; <code>false</code> incorrect
* password
*/
boolean verifyKey(String inputPassword);
/**
* Allow reading of configured parameters.
*
* @return Currently set parameters.
*/
PBKDF2Parameters getParameters();
/**
* Allow setting of configured parameters.
*
* @param parameters PBKDF2Parameters
*/
void setParameters(PBKDF2Parameters parameters);
/**
* Get currently set Pseudo Random Function.
*
* @return Currently set Pseudo Random Function
*/
PRF getPseudoRandomFunction();
/**
* Set the Pseudo Random Function to use. Note that deriveKeys/getPRF does
* init this object using the supplied candidate password. If this is
* undesired, one has to override getPRF.
*
* @param prf Pseudo Random Function to set.
*/
void setPseudoRandomFunction(PRF prf);
}

View File

@ -1,346 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* <p>
* Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification
* </p><p>
* Version 2.0
* </p>
* <p>
* PBKDF2 (P, S, c, dkLen)
* </p>
* Options:
* <ul>
* <li>PRF underlying pseudorandom function (hLen denotes the length in octets
* of the pseudorandom function output). PRF is pluggable.</li>
* </ul>
* Input:
* <ul>
* <li>P password, an octet string</li>
* <li>S salt, an octet string</li>
* <li>c iteration count, a positive integer</li>
* <li>dkLen intended length in octets of the derived key, a positive integer,
* at most (2^32 - 1) * hLen</li>
* </ul>
* Output:
* <ul>
* <li>DK derived key, a dkLen-octet string</li>
* </ul>
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see
* <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" >http://www.
* gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;rtner
* @version 1.0
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898</a>
*/
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
* &quot;Salt:iteration-count:PBKDF2&quot; with binary data in hexadecimal
* encoding.
* <p>
* Example: Password &quot;password&quot; (without the quotes) leads to
* 48290A0B96C426C3:1000:973899B1D4AFEB3ED371060D0797E0EE0142BD04
* </p>
* @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. <code>null</code> means no salt.
* @param c Iteration count (see RFC 2898 4.2)
* @param dkLen desired length of derived key.
*
* @return internal byte array * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2</a>
*/
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 <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 2.</a>
*/
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 <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 3.</a>
*/
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 <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 3.</a>
*/
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;
}
}

View File

@ -1,56 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/**
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;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 <code>false</code> syntax OK, <code>true</code> some syntax
* issue.
*/
boolean fromString(PBKDF2Parameters p, String s);
}

View File

@ -1,62 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/**
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;rtner
* @version 1.0
*/
public class PBKDF2HexFormatter implements PBKDF2Formatter {
@Override
public boolean fromString(PBKDF2Parameters p, String s) {
if (p == null || s == null) {
return true;
}
String[] p123 = s.split(":");
if (p123.length != 3) {
return true;
}
byte salt[] = BinTools.hex2bin(p123[0]);
int iterationCount = Integer.parseInt(p123[1]);
byte bDK[] = BinTools.hex2bin(p123[2]);
p.setSalt(salt);
p.setIterationCount(iterationCount);
p.setDerivedKey(bDK);
return false;
}
@Override
public String toString(PBKDF2Parameters p) {
String s = BinTools.bin2hex(p.getSalt()) + ":" + String.valueOf(p.getIterationCount()) + ":" + BinTools.bin2hex(p.getDerivedKey());
return s;
}
}

View File

@ -1,139 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/**
* <p>
* Parameter data holder for PBKDF2 configuration.
* </p>
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;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 <code>null</code> 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 <code>null</code> (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 <code>null</code> (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;
}
}

View File

@ -1,60 +0,0 @@
package fr.xephi.authme.security.pbkdf2;
/**
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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
* </p>
* <p>
* For Details, see <a
* href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
* >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
* </p>
*
* @author Matthias G&auml;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();
}

View File

@ -7,10 +7,11 @@ import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.settings.properties.ProtectionSettings;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import javax.inject.Inject; import javax.inject.Inject;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE; 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 Messages messages;
private final PermissionsManager permissionsManager; private final PermissionsManager permissionsManager;
private final BukkitService bukkitService; private final BukkitService bukkitService;
private final CopyOnWriteArrayList<String> antibotKicked = new CopyOnWriteArrayList<>();
// Settings // Settings
private int duration; private int duration;
private int sensibility; private int sensibility;
private int delay; private int delay;
private int interval;
// Service status // Service status
private AntiBotStatus antiBotStatus; private AntiBotStatus antiBotStatus;
private boolean startup; private boolean startup;
private BukkitTask disableTask; private BukkitTask disableTask;
private int antibotPlayers; private Instant lastFlaggedJoin;
private final CopyOnWriteArrayList<String> antibotKicked = new CopyOnWriteArrayList<>(); private int flagged = 0;
@Inject @Inject
AntiBotService(Settings settings, Messages messages, PermissionsManager permissionsManager, AntiBotService(Settings settings, Messages messages, PermissionsManager permissionsManager,
@ -47,7 +48,7 @@ public class AntiBotService implements SettingsDependent {
this.bukkitService = bukkitService; this.bukkitService = bukkitService;
// Initial status // Initial status
disableTask = null; disableTask = null;
antibotPlayers = 0; flagged = 0;
antiBotStatus = AntiBotStatus.DISABLED; antiBotStatus = AntiBotStatus.DISABLED;
startup = true; startup = true;
// Load settings and start if required // Load settings and start if required
@ -60,6 +61,7 @@ public class AntiBotService implements SettingsDependent {
duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION); duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION);
sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY); sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY);
delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY); delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY);
interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL);
// Stop existing protection // Stop existing protection
stopProtection(); stopProtection();
@ -71,15 +73,10 @@ public class AntiBotService implements SettingsDependent {
} }
// Bot activation task // Bot activation task
Runnable enableTask = new Runnable() { Runnable enableTask = () -> antiBotStatus = AntiBotStatus.LISTENING;
@Override
public void run() {
antiBotStatus = AntiBotStatus.LISTENING;
}
};
// Delay the schedule on first start // Delay the schedule on first start
if(startup) { if (startup) {
bukkitService.scheduleSyncDelayedTask(enableTask, delay * TICKS_PER_SECOND); bukkitService.scheduleSyncDelayedTask(enableTask, delay * TICKS_PER_SECOND);
startup = false; startup = false;
} else { } else {
@ -94,19 +91,12 @@ public class AntiBotService implements SettingsDependent {
antiBotStatus = AntiBotStatus.ACTIVE; antiBotStatus = AntiBotStatus.ACTIVE;
// Inform admins // Inform admins
for (Player player : bukkitService.getOnlinePlayers()) { bukkitService.getOnlinePlayers().stream()
if (permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) { .filter(player -> permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES))
messages.send(player, MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE); .forEach(player -> messages.send(player, MessageKey.ANTIBOT_AUTO_ENABLED_MESSAGE));
}
}
// Schedule auto-disable // Schedule auto-disable
disableTask = bukkitService.runTaskLater(new Runnable() { disableTask = bukkitService.runTaskLater(this::stopProtection, duration * TICKS_PER_MINUTE);
@Override
public void run() {
stopProtection();
}
}, duration * TICKS_PER_MINUTE);
} }
private void stopProtection() { private void stopProtection() {
@ -116,7 +106,7 @@ public class AntiBotService implements SettingsDependent {
// Change status // Change status
antiBotStatus = AntiBotStatus.LISTENING; antiBotStatus = AntiBotStatus.LISTENING;
antibotPlayers = 0; flagged = 0;
antibotKicked.clear(); antibotKicked.clear();
// Cancel auto-disable task // Cancel auto-disable task
@ -124,11 +114,10 @@ public class AntiBotService implements SettingsDependent {
disableTask = null; disableTask = null;
// Inform admins // Inform admins
for (Player player : bukkitService.getOnlinePlayers()) { String durationString = Integer.toString(duration);
if (permissionsManager.hasPermission(player, AdminPermission.ANTIBOT_MESSAGES)) { bukkitService.getOnlinePlayers().stream()
messages.send(player, MessageKey.ANTIBOT_AUTO_DISABLED_MESSAGE, Integer.toString(duration)); .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. * 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 * @return if the player should be kicked
*/ */
public boolean shouldKick(boolean isAuthAvailable) { public boolean shouldKick() {
return !isAuthAvailable && (antiBotStatus == AntiBotStatus.ACTIVE); 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;
} }
/** /**

View File

@ -104,36 +104,22 @@ public class BackupService {
dirBackup.mkdir(); dirBackup.mkdir();
} }
String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH); String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH);
if (checkWindows(backupWindowsPath)) { boolean isUsingWindows = checkWindows(backupWindowsPath);
String executeCmd = backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql"; String backupCommand = isUsingWindows
Process runtimeProcess; ? backupWindowsPath + "\\bin\\mysqldump.exe" + buildMysqlDumpArguments()
try { : "mysqldump" + buildMysqlDumpArguments();
runtimeProcess = Runtime.getRuntime().exec(executeCmd);
int processComplete = runtimeProcess.waitFor(); try {
if (processComplete == 0) { Process runtimeProcess = Runtime.getRuntime().exec(backupCommand);
ConsoleLogger.info("Backup created successfully."); int processComplete = runtimeProcess.waitFor();
return true; if (processComplete == 0) {
} else { ConsoleLogger.info("Backup created successfully. (Using Windows = " + isUsingWindows + ")");
ConsoleLogger.warning("Could not create the backup! (Windows)"); return true;
} } else {
} catch (IOException | InterruptedException e) { ConsoleLogger.warning("Could not create the backup! (Using Windows = " + isUsingWindows + ")");
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);
} }
} catch (IOException | InterruptedException e) {
ConsoleLogger.logException("Error during backup (using Windows = " + isUsingWindows + "):", e);
} }
return false; return false;
} }
@ -173,6 +159,16 @@ public class BackupService {
return false; 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 { private static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src); InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst); OutputStream out = new FileOutputStream(dst);

View File

@ -10,6 +10,7 @@ import org.bukkit.BanList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -17,6 +18,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
@ -40,7 +42,8 @@ public class BukkitService implements SettingsDependent {
private Method getOnlinePlayers; private Method getOnlinePlayers;
private boolean useAsyncTasks; private boolean useAsyncTasks;
public BukkitService(AuthMe authMe, Settings settings) { @Inject
BukkitService(AuthMe authMe, Settings settings) {
this.authMe = authMe; this.authMe = authMe;
getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField(); getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField();
reload(settings); reload(settings);
@ -271,6 +274,27 @@ public class BukkitService implements SettingsDependent {
return Bukkit.getWorld(name); return Bukkit.getWorld(name);
} }
/**
* Dispatches a command on this server, and executes it if found.
*
* @param sender the apparent sender of the command
* @param commandLine the command + arguments. Example: <code>test abc 123</code>
* @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: <code>test abc 123</code>
* @return returns false if no target is found
*/
public boolean dispatchConsoleCommand(String commandLine) {
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), commandLine);
}
@Override @Override
public void reload(Settings settings) { public void reload(Settings settings) {
useAsyncTasks = settings.getProperty(PluginSettings.USE_ASYNC_TASKS); 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) { public BanEntry banIp(String ip, String reason, Date expires, String source) {
return Bukkit.getServer().getBanList(BanList.Type.IP).addBan(ip, reason, expires, source); return Bukkit.getServer().getBanList(BanList.Type.IP).addBan(ip, reason, expires, source);
} }
} }

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.process; package fr.xephi.authme.service;
import com.github.authme.configme.properties.Property; import com.github.authme.configme.properties.Property;
import fr.xephi.authme.message.MessageKey; 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.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; 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 @Inject
private Settings settings; private Settings settings;
@ -25,17 +24,17 @@ public class ProcessService {
@Inject @Inject
private Messages messages; private Messages messages;
@Inject
private ValidationService validationService;
@Inject @Inject
private PermissionsManager permissionsManager; private PermissionsManager permissionsManager;
@Inject @Inject
private AuthGroupHandler authGroupHandler; private AuthGroupHandler authGroupHandler;
CommonService() {
}
/** /**
* Retrieve a property's value. * Retrieves a property's value.
* *
* @param property the property to retrieve * @param property the property to retrieve
* @param <T> the property type * @param <T> the property type
@ -46,16 +45,7 @@ public class ProcessService {
} }
/** /**
* Return the settings manager. * Sends a message to the command sender.
*
* @return settings manager
*/
public Settings getSettings() {
return settings;
}
/**
* Send a message to the command sender.
* *
* @param sender the command sender * @param sender the command sender
* @param key the message key * @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 sender the command sender
* @param key the message key * @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 * @param key the key of the message
* @return the message, split by line * @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 * @param key the key of the message
* @return the message * @return the message
@ -95,18 +85,24 @@ public class ProcessService {
return messages.retrieveSingle(key); return messages.retrieveSingle(key);
} }
public boolean validateEmail(String email) { /**
return validationService.validateEmail(email); * Checks whether the player has the given permission.
} *
* @param player the player
public boolean isEmailFreeForRegistration(String email, CommandSender sender) { * @param node the permission node to check
return validationService.isEmailFreeForRegistration(email, sender); * @return true if player has permission, false otherwise
} */
public boolean hasPermission(Player player, PermissionNode node) { public boolean hasPermission(Player player, PermissionNode node) {
return permissionsManager.hasPermission(player, 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) { public boolean setGroup(Player player, AuthGroupType group) {
return authGroupHandler.setGroup(player, group); return authGroupHandler.setGroup(player, group);
} }

View File

@ -17,6 +17,8 @@ import java.net.URLConnection;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import static com.maxmind.geoip.LookupService.GEOIP_MEMORY_CACHE;
public class GeoIpService { public class GeoIpService {
private static final String LICENSE = private static final String LICENSE =
"[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com"; "[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); boolean dataIsOld = (System.currentTimeMillis() - dataFile.lastModified()) > TimeUnit.DAYS.toMillis(30);
if (!dataIsOld) { if (!dataIsOld) {
try { try {
lookupService = new LookupService(dataFile); lookupService = new LookupService(dataFile, GEOIP_MEMORY_CACHE);
ConsoleLogger.info(LICENSE); ConsoleLogger.info(LICENSE);
return true; return true;
} catch (IOException e) { } catch (IOException e) {

View File

@ -57,7 +57,7 @@ public class MessageUpdater {
properties = buildPropertyEntriesForMessageKeys(); properties = buildPropertyEntriesForMessageKeys();
settingsManager = new SettingsManager( 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() { private void copyMissingMessages() {
for (Property<String> property : properties) { for (Property<String> property : properties) {
String message = userConfiguration.getString(property.getPath()); String message = userConfiguration.getString(property.getPath());

View File

@ -40,7 +40,8 @@ public class ValidationService implements Reloadable {
private Pattern passwordRegex; private Pattern passwordRegex;
private Set<String> unrestrictedNames; private Set<String> unrestrictedNames;
ValidationService() { } ValidationService() {
}
@PostConstruct @PostConstruct
@Override @Override

View File

@ -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<E extends Enum<E>> extends StringListProperty {
private final Class<E> enumClass;
public EnumSetProperty(Class<E> 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<E> asEnumSet(SettingsManager settings) {
List<String> 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;
}
}

Some files were not shown because too many files have changed in this diff Show More