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"><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>
#####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)
- Dependencies: [![Dependency Status](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d/badge.svg)](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
- 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>
- Development resources:
- <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">JavaDocs</a>
- <a href="http://ci.xephi.fr/plugin/repository/everything/">Maven Repository</a>
#####Statistics:
@ -38,25 +34,21 @@ McStats: http://mcstats.org/plugin/AuthMe
<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>
#####Compiling Requirements:
#####Compiling requirements:
>- JDK 1.8
>- Maven
>- Git/Github (Optional)
#####How to compile the project:
>- Clone the project with Git/Github
>- Execute command "mvn clean install"
>- Execute command "mvn clean package"
#####Running Requirements:
#####Running requirements:
>- Java 1.8
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X)
>- ProtocolLib (optional, required by the protectInventory feature)
>- TacoSpigot, PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X, 1.11.X)
>- ProtocolLib (optional, required by some features)
<hr>
###Plugin Description:
@ -102,19 +94,19 @@ You can also create your own translation file and, if you want, you can share it
</ul></li>
<li>Custom MySQL tables/columns names (useful with forums databases)</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>Restricted users (associate a Username with an IP)</li>
<li>Protect player's inventory until a correct Authentication</li>
<li>Restricted users (associate a username with an IP)</li>
<li>Protect player's inventory until correct authentication (requires ProtocolLib)</li>
<li>Saves the quit location of the player</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>Automatic database backup</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><strong>Import your old database from other plugins like Rakamak, xAuth, CrazyLogin, RoyalAuth and vAuth!</strong></li>
</ul>
####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
<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
@ -125,30 +117,21 @@ You can also create your own translation file and, if you want, you can share it
- [List of all permission nodes](http://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md)
####How To
- [How to install and set up](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-install-and-initial-configuration/)
- [How to import database from xAuth](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-xauth/)
- [Website integration](http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/)
- [Click here for an example of the config file](https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml)
- [How to convert from Rakamak](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/)
- Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
- Convert between database types (e.g. SQLite to MySQL): /authme converter
<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
GameHosting.it is leader in Italy as Game Server Provider. With its own DataCenter offers Anti-DDoS solutions at affordable prices. Game Server of Minecraft based on Multicraft are equipped with the latest technology in hardware.
[![GameHosting](http://www.gamehosting.it/images/bn3.png)](http://www.gamehosting.it)
#####Credits
<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>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-legacy.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS/AuthMe.jar
- mkdir -p $CIRCLE_TEST_REPORTS/junit/
- find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
notify:
webhooks:
- url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf

View File

@ -1,5 +1,5 @@
<!-- 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
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.
<br />Requires `authme.player.changepassword`
- **/changepassword help** [query]: View detailed help for /changepassword commands.
- **/email**: The AuthMeReloaded Email command base.
- **/email**: The AuthMeReloaded email command base.
- **/email show**: Show your current email address.
- **/email add** &lt;email> &lt;verifyEmail>: Add a new email address to your account.
<br />Requires `authme.player.email.add`
- **/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`
- **/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 -->
<!-- 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
AuthMe supports the following hash algorithms for storing your passwords safely.
@ -13,11 +13,11 @@ CRAZYCRYPT1 | Do not use | 128 | | | Username | |
DOUBLEMD5 | Do not use | 32 | | | None | |
IPB3 | Acceptable | 32 | | | Text | 5 | Y
IPB4 | Does not work | 60 | | | Text | 22 | Y
JOOMLA | Recommended | 65 | | | Text | 32 |
JOOMLA | Acceptable | 65 | | | Text | 32 |
MD5 | Do not use | 32 | | | None | |
MD5VB | Acceptable | 56 | | | Text | 16 |
MYBB | Acceptable | 32 | | | Text | 8 | Y
PBKDF2 | Does not work | 332 | | | Text | 12 |
PBKDF2 | Recommended | 165 | | | Text | 16 |
PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 |
PHPBB | Acceptable | 34 | | | Text | 16 |
PHPFUSION | Do not use | 64 | Y | | | | Y
@ -82,4 +82,4 @@ or bad.
---
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Oct 01 23:42:20 CEST 2016
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Fri Nov 25 15:48:35 CET 2016

View File

@ -1,5 +1,5 @@
<!-- 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
The following are the permission nodes that are currently supported by the latest dev builds.
@ -38,15 +38,15 @@ The following are the permission nodes that are currently supported by the lates
- **authme.player.email** Grants all email permissions.
- **authme.player.email.add** Command permission to add an email address.
- **authme.player.email.change** Command permission to change the email address.
- **authme.player.email.recover** Command permission to recover an account using it's email address.
- **authme.player.email.recover** Command permission to recover an account using its email address.
- **authme.player.login** Command permission to login.
- **authme.player.logout** Command permission to logout.
- **authme.player.register** Command permission to register.
- **authme.player.seeownaccounts** Permission to use to see own other accounts.
- **authme.player.unregister** Command permission to unregister.
- **authme.vip** Permission node to identify VIP users.
- **authme.vip** When the server is full and someone with this permission joins the server, someone will be kicked.
---
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:10 CEST 2016
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 15:38:58 CEST 2016

View File

@ -1,5 +1,5 @@
<!-- 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
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;
---- | -------- | ---------: | ------
[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" />
[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" />
[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" />
[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 | 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" />
[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" />
[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" />
[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" />
[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" />
[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 | 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 | 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 | 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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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 | 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 | 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 | 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 | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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" />
[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>
<!-- Change Bukkit Version HERE! -->
<bukkit.version>1.10.2-R0.1-SNAPSHOT</bukkit.version>
<bukkit.version>1.11-R0.1-SNAPSHOT</bukkit.version>
</properties>
<!-- Jenkins profile -->
@ -196,7 +196,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<version>3.6.0</version>
<configuration>
<source>${project.jdkVersion}</source>
<target>${project.jdkVersion}</target>
@ -268,6 +268,10 @@
<pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
</relocation>
<relocation>
<pattern>de.rtner</pattern>
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
</relocation>
<relocation>
<pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
@ -319,6 +323,10 @@
<pattern>net.ricecode.similarity</pattern>
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
</relocation>
<relocation>
<pattern>de.rtner</pattern>
<shadedPattern>fr.xephi.authme.libs.de.rtner</shadedPattern>
</relocation>
<relocation>
<pattern>javax.inject</pattern>
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
@ -524,6 +532,13 @@
<optional>true</optional>
</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/ -->
<!-- Moved in profiles! -->
@ -873,7 +888,7 @@
<dependency>
<groupId>com.github.authme</groupId>
<artifactId>configme</artifactId>
<version>0.2</version>
<version>0.2.1</version>
<scope>compile</scope>
<optional>true</optional>
<exclusions>
@ -904,7 +919,7 @@
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
<version>2.0.5-beta</version>
<version>2.2.27</version>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
@ -917,13 +932,13 @@
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<version>3.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.192</version>
<version>1.4.193</version>
<scope>test</scope>
</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)
*/
private function getHashFromDatabase($username) {
// Add here your database host, username, password and database name
$mysqli = $this->getAuthmeMySqli();
if ($mysqli !== null) {
$stmt = $mysqli->prepare('SELECT password FROM ' . self::AUTHME_TABLE . ' WHERE username = ?');

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

View File

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

View File

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

View File

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

View File

@ -87,10 +87,10 @@ public class CommandMapper {
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
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);
@ -115,7 +115,7 @@ public class CommandMapper {
final int partsSize = parts.size();
List<String> labels = parts.subList(0, Math.min(closestCommand.getLabelCount(), partsSize));
List<String> arguments = (labels.size() == partsSize)
? new ArrayList<String>()
? new ArrayList<>()
: parts.subList(labels.size(), partsSize);
return new FoundCommandResult(closestCommand, labels, arguments, minDifference, status);
@ -141,7 +141,7 @@ public class CommandMapper {
*
* @return A command if there was a complete match (including proper argument count), null otherwise
*/
private CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
private static CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
if (CollectionUtils.isEmpty(parts)) {
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;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@ -23,7 +23,7 @@ public class AccountsCommand implements ExecutableCommand {
private BukkitService bukkitService;
@Inject
private CommandService commandService;
private CommonService commonService;
@Override
public void executeCommand(final CommandSender sender, List<String> arguments) {
@ -50,13 +50,13 @@ public class AccountsCommand implements ExecutableCommand {
public void run() {
PlayerAuth auth = dataSource.getAuth(playerName.toLowerCase());
if (auth == null) {
commandService.send(sender, MessageKey.UNKNOWN_USER);
commonService.send(sender, MessageKey.UNKNOWN_USER);
return;
}
List<String> accountList = dataSource.getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
commonService.send(sender, MessageKey.USER_NOT_REGISTERED);
} else if (accountList.size() == 1) {
sender.sendMessage("[AuthMe] " + playerName + " is a single account player");
} else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,9 +3,6 @@ package fr.xephi.authme.datasource;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
@ -397,7 +394,7 @@ public class SQLite implements DataSource {
}
}
private void close(Statement st) {
private static void close(Statement st) {
if (st != null) {
try {
st.close();
@ -407,7 +404,7 @@ public class SQLite implements DataSource {
}
}
private void close(Connection con) {
private static void close(Connection con) {
if (con != null) {
try {
con.close();
@ -417,7 +414,7 @@ public class SQLite implements DataSource {
}
}
private void close(ResultSet rs) {
private static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
@ -479,7 +476,7 @@ public class SQLite implements DataSource {
pst.setString(1, user);
rs = pst.executeQuery();
if (rs.next())
return (rs.getInt(col.IS_LOGGED) == 1);
return rs.getInt(col.IS_LOGGED) == 1;
} catch (SQLException ex) {
logSqlException(ex);
} finally {

View File

@ -43,20 +43,7 @@ public class CrazyLoginConverter implements Converter {
try (BufferedReader users = new BufferedReader(new FileReader(source))) {
while ((line = users.readLine()) != null) {
if (line.contains("|")) {
String[] args = line.split("\\|");
if (args.length < 2 || "name".equalsIgnoreCase(args[0])) {
continue;
}
String playerName = args[0];
String password = args[1];
if (password != null) {
PlayerAuth auth = PlayerAuth.builder()
.name(playerName.toLowerCase())
.realName(playerName)
.password(password, null)
.build();
database.saveAuth(auth);
}
migrateAccount(line);
}
}
ConsoleLogger.info("CrazyLogin database has been imported correctly");
@ -66,4 +53,26 @@ public class CrazyLoginConverter implements Converter {
}
}
/**
* Moves an account from CrazyLogin to the AuthMe database.
*
* @param line line read from the CrazyLogin file (one account)
*/
private void migrateAccount(String line) {
String[] args = line.split("\\|");
if (args.length < 2 || "name".equalsIgnoreCase(args[0])) {
return;
}
String playerName = args[0];
String password = args[1];
if (password != null) {
PlayerAuth auth = PlayerAuth.builder()
.name(playerName.toLowerCase())
.realName(playerName)
.password(password, null)
.build();
database.saveAuth(auth);
}
}
}

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
* and that can be cleaned up periodically.
*
* @see fr.xephi.authme.task.CleanupTask
*/
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);
}
if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
&& !settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
if (!limboPlayerStorage.hasData(player)) {
limboPlayerStorage.saveData(player);
}
&& !settings.getProperty(RestrictionSettings.NO_TELEPORT) && !limboPlayerStorage.hasData(player)) {
limboPlayerStorage.saveData(player);
}
}
}

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

View File

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

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;
import fr.xephi.authme.AuthMe;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.bukkit.Server;
import javax.activation.CommandMap;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.mail.Session;
@ -27,18 +30,19 @@ import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
/**
* @author Xephi59
* Sends emails to players on behalf of the server.
*/
public class SendMailSSL {
@Inject
private AuthMe plugin;
@Inject
private Settings settings;
@Inject
private BukkitService bukkitService;
private final File dataFolder;
private final String serverName;
private final Settings settings;
SendMailSSL() {
@Inject
SendMailSSL(@DataFolder File dataFolder, Server server, Settings settings) {
this.dataFolder = dataFolder;
this.serverName = server.getServerName();
this.settings = settings;
}
/**
@ -57,62 +61,57 @@ public class SendMailSSL {
* @param name the name of the player
* @param mailAddress the player's email
* @param newPass the new password
* @return true if email could be sent, false otherwise
*/
public void sendPasswordMail(String name, String mailAddress, String newPass) {
public boolean sendPasswordMail(String name, String mailAddress, String newPass) {
if (!hasAllInformation()) {
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
return;
return false;
}
final String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
bukkitService.runTaskAsynchronously(new Runnable() {
HtmlEmail email;
try {
email = initializeMail(mailAddress);
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email with the given settings:", e);
return false;
}
@Override
public void run() {
HtmlEmail email;
try {
email = initializeMail(mailAddress);
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email with the given settings:", e);
return;
}
String content = mailText;
// Generate an image?
File file = null;
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
file = generateImage(name, plugin, newPass);
content = embedImageIntoEmailContent(file, email, content);
} catch (IOException | EmailException e) {
ConsoleLogger.logException(
"Unable to send new password as image for email " + mailAddress + ":", e);
}
}
sendEmail(content, email);
FileUtils.delete(file);
String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass);
// Generate an image?
File file = null;
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
file = generateImage(name, newPass);
mailText = embedImageIntoEmailContent(file, email, mailText);
} catch (IOException | EmailException e) {
ConsoleLogger.logException(
"Unable to send new password as image for email " + mailAddress + ":", e);
}
});
}
boolean couldSendEmail = sendEmail(mailText, email);
FileUtils.delete(file);
return couldSendEmail;
}
public void sendRecoveryCode(String name, String email, String code) {
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
public boolean sendRecoveryCode(String name, String email, String code) {
HtmlEmail htmlEmail;
try {
htmlEmail = initializeMail(email);
} catch (EmailException e) {
ConsoleLogger.logException("Failed to create email for recovery code:", e);
return;
return false;
}
sendEmail(message, htmlEmail);
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
return sendEmail(message, htmlEmail);
}
private static File generateImage(String name, AuthMe plugin, String newPass) throws IOException {
private File generateImage(String name, String newPass) throws IOException {
ImageGenerator gen = new ImageGenerator(newPass);
File file = new File(plugin.getDataFolder(), name + "_new_pass.jpg");
File file = new File(dataFolder, name + "_new_pass.jpg");
ImageIO.write(gen.generateImage(), "jpg", file);
return file;
}
@ -124,7 +123,8 @@ public class SendMailSSL {
return content.replace("<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 senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail
@ -145,8 +145,18 @@ public class SendMailSSL {
return email;
}
private static boolean sendEmail(String content, HtmlEmail email) {
@VisibleForTesting
boolean sendEmail(String content, HtmlEmail email) {
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader());
// Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative
// cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type
MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822");
try {
email.setHtmlMsg(content);
email.setTextMsg(content);
@ -166,14 +176,14 @@ public class SendMailSSL {
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
return mailText
.replace("<playername />", name)
.replace("<servername />", plugin.getServer().getServerName())
.replace("<servername />", serverName)
.replace("<generatedpass />", newPass);
}
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
return mailText
.replace("<playername />", name)
.replace("<servername />", plugin.getServer().getServerName())
.replace("<servername />", serverName)
.replace("<recoverycode />", code)
.replace("<hoursvalid />", String.valueOf(hoursValid));
}

View File

@ -53,7 +53,7 @@ public class MessageFileHandler {
if (message == null) {
ConsoleLogger.warning("Error getting message with key '" + key + "'. "
+ "Please verify your config file at '" + filename + "'");
+ "Please update your config file '" + filename + "' (or run /authme messages)");
return getDefault(key);
}
return message;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@ public enum PlayerStatePermission implements PermissionNode {
BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY),
/**
* Permission node to identify VIP users.
* When the server is full and someone with this permission joins the server, someone will be kicked.
*/
IS_VIP("authme.vip", DefaultPermission.OP_ONLY),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,15 +4,15 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.process.ProcessService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.task.LimboPlayerTaskManager;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@ -25,7 +25,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
private BungeeService bungeeService;
@Inject
private ProcessService service;
private CommonService service;
@Inject
private LimboCache limboCache;
@ -33,17 +33,10 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
@Inject
private LimboPlayerTaskManager limboPlayerTaskManager;
ProcessSyncPasswordRegister() {
}
@Inject
private CommandManager commandManager;
private void forceCommands(Player player) {
for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS)) {
player.performCommand(command.replace("%p", player.getName()));
}
for (String command : service.getProperty(RegistrationSettings.FORCE_REGISTER_COMMANDS_AS_CONSOLE)) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(),
command.replace("%p", player.getName()));
}
ProcessSyncPasswordRegister() {
}
/**
@ -83,7 +76,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
}
// Register is now finished; we can force all commands
forceCommands(player);
commandManager.runCommandsOnRegister(player);
// Request login after registration
if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) {

View File

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

View File

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

View File

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

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.Usage;
@Recommendation(Usage.RECOMMENDED)
@Recommendation(Usage.ACCEPTABLE)
public class JOOMLA extends HexSaltedMethod {
@Override

View File

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

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

View File

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

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.process;
package fr.xephi.authme.service;
import com.github.authme.configme.properties.Property;
import fr.xephi.authme.message.MessageKey;
@ -8,16 +8,15 @@ import fr.xephi.authme.permission.AuthGroupType;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Service for asynchronous and synchronous processes.
* Service for the most common operations regarding settings, messages and permissions.
*/
public class ProcessService {
public class CommonService {
@Inject
private Settings settings;
@ -25,17 +24,17 @@ public class ProcessService {
@Inject
private Messages messages;
@Inject
private ValidationService validationService;
@Inject
private PermissionsManager permissionsManager;
@Inject
private AuthGroupHandler authGroupHandler;
CommonService() {
}
/**
* Retrieve a property's value.
* Retrieves a property's value.
*
* @param property the property to retrieve
* @param <T> the property type
@ -46,16 +45,7 @@ public class ProcessService {
}
/**
* Return the settings manager.
*
* @return settings manager
*/
public Settings getSettings() {
return settings;
}
/**
* Send a message to the command sender.
* Sends a message to the command sender.
*
* @param sender the command sender
* @param key the message key
@ -65,7 +55,7 @@ public class ProcessService {
}
/**
* Send a message to the command sender with the given replacements.
* Sends a message to the command sender with the given replacements.
*
* @param sender the command sender
* @param key the message key
@ -76,7 +66,7 @@ public class ProcessService {
}
/**
* Retrieve a message.
* Retrieves a message.
*
* @param key the key of the message
* @return the message, split by line
@ -86,7 +76,7 @@ public class ProcessService {
}
/**
* Retrieve a message as one piece.
* Retrieves a message in one piece.
*
* @param key the key of the message
* @return the message
@ -95,18 +85,24 @@ public class ProcessService {
return messages.retrieveSingle(key);
}
public boolean validateEmail(String email) {
return validationService.validateEmail(email);
}
public boolean isEmailFreeForRegistration(String email, CommandSender sender) {
return validationService.isEmailFreeForRegistration(email, sender);
}
/**
* Checks whether the player has the given permission.
*
* @param player the player
* @param node the permission node to check
* @return true if player has permission, false otherwise
*/
public boolean hasPermission(Player player, PermissionNode node) {
return permissionsManager.hasPermission(player, node);
}
/**
* Sets the permission group of the given player.
*
* @param player the player to process
* @param group the group to add the player to
* @return true on success, false otherwise
*/
public boolean setGroup(Player player, AuthGroupType group) {
return authGroupHandler.setGroup(player, group);
}

View File

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

View File

@ -57,7 +57,7 @@ public class MessageUpdater {
properties = buildPropertyEntriesForMessageKeys();
settingsManager = new SettingsManager(
new YamlFileResource(userFile), (r, p) -> true, new ConfigurationData((List) properties));
new YamlFileResource(userFile), null, new ConfigurationData(properties));
}
/**
@ -85,7 +85,6 @@ public class MessageUpdater {
}
}
@SuppressWarnings("unchecked")
private void copyMissingMessages() {
for (Property<String> property : properties) {
String message = userConfiguration.getString(property.getPath());

View File

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