mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-20 01:05:12 +01:00
Merge branch 'master' into 745-captcha-login-message
This commit is contained in:
commit
fae7286776
83
README.md
83
README.md
@ -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&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&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
|
||||
|
@ -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
|
||||
|
@ -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** <oldPassword> <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** <email> <verifyEmail>: Add a new email address to your account.
|
||||
<br />Requires `authme.player.email.add`
|
||||
- **/email change** <oldEmail> <newEmail>: Change an email address of your account.
|
||||
@ -75,7 +76,6 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
|
||||
<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
467
docs/config.md
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
---- | -------- | ---------: | ------
|
||||
[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
27
pom.xml
@ -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>
|
||||
|
||||
|
@ -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 = ?');
|
||||
|
53
samples/website_integration/Pbkdf2.php
Normal file
53
samples/website_integration/Pbkdf2.php
Normal 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'));
|
||||
}
|
||||
}
|
@ -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'));
|
||||
}
|
||||
|
||||
|
@ -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!");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
127
src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java
Normal file
127
src/main/java/fr/xephi/authme/initialization/OnStartupTasks.java
Normal 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));
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package fr.xephi.authme.initialization;
|
||||
|
||||
/**
|
||||
* Interface for reloadable entities.
|
||||
*
|
||||
* @see fr.xephi.authme.command.executable.authme.ReloadCommand
|
||||
*/
|
||||
public interface Reloadable {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -5,156 +5,235 @@ package fr.xephi.authme.message;
|
||||
*/
|
||||
public enum MessageKey {
|
||||
|
||||
/** In order to use this command you must be authenticated! */
|
||||
DENIED_COMMAND("denied_command"),
|
||||
|
||||
/** A player with the same IP is already in game! */
|
||||
SAME_IP_ONLINE("same_ip_online"),
|
||||
|
||||
/** In order to chat you must be authenticated! */
|
||||
DENIED_CHAT("denied_chat"),
|
||||
|
||||
/** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */
|
||||
KICK_ANTIBOT("kick_antibot"),
|
||||
|
||||
/** Can't find the requested user in the database! */
|
||||
UNKNOWN_USER("unknown_user"),
|
||||
|
||||
/** Your quit location was unsafe, you have been teleported to the world's spawnpoint. */
|
||||
UNSAFE_QUIT_LOCATION("unsafe_spawn"),
|
||||
|
||||
/** You're not logged in! */
|
||||
NOT_LOGGED_IN("not_logged_in"),
|
||||
|
||||
/** You can register yourself to the server with the command "/register >password> >ConfirmPassword>" */
|
||||
REGISTER_VOLUNTARILY("reg_voluntarily"),
|
||||
|
||||
/** Usage: /login >password> */
|
||||
USAGE_LOGIN("usage_log"),
|
||||
|
||||
/** Wrong password! */
|
||||
WRONG_PASSWORD("wrong_pwd"),
|
||||
|
||||
/** Successfully unregistered! */
|
||||
UNREGISTERED_SUCCESS("unregistered"),
|
||||
|
||||
/** In-game registration is disabled! */
|
||||
REGISTRATION_DISABLED("reg_disabled"),
|
||||
|
||||
/** Logged-in due to Session Reconnection. */
|
||||
SESSION_RECONNECTION("valid_session"),
|
||||
|
||||
/** Successful login! */
|
||||
LOGIN_SUCCESS("login"),
|
||||
|
||||
/** Your account isn't activated yet, please check your emails! */
|
||||
ACCOUNT_NOT_ACTIVATED("vb_nonActiv"),
|
||||
|
||||
/** You already have registered this username! */
|
||||
NAME_ALREADY_REGISTERED("user_regged"),
|
||||
|
||||
/** You don't have the permission to perform this action! */
|
||||
NO_PERMISSION("no_perm"),
|
||||
|
||||
/** An unexpected error occurred, please contact an administrator! */
|
||||
ERROR("error"),
|
||||
|
||||
/** Please, login with the command "/login >password>" */
|
||||
LOGIN_MESSAGE("login_msg"),
|
||||
|
||||
/** Please, register to the server with the command "/register >password> >ConfirmPassword>" */
|
||||
REGISTER_MESSAGE("reg_msg"),
|
||||
|
||||
/** Please, register to the server with the command "/register >email> >confirmEmail>" */
|
||||
REGISTER_EMAIL_MESSAGE("reg_email_msg"),
|
||||
|
||||
/** You have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection! */
|
||||
MAX_REGISTER_EXCEEDED("max_reg", "%max_acc", "%reg_count", "%reg_names"),
|
||||
|
||||
/** Usage: /register >password> >ConfirmPassword> */
|
||||
USAGE_REGISTER("usage_reg"),
|
||||
|
||||
/** Usage: /unregister >password> */
|
||||
USAGE_UNREGISTER("usage_unreg"),
|
||||
|
||||
/** Password changed successfully! */
|
||||
PASSWORD_CHANGED_SUCCESS("pwd_changed"),
|
||||
|
||||
/** This user isn't registered! */
|
||||
USER_NOT_REGISTERED("user_unknown"),
|
||||
|
||||
/** Passwords didn't match, check them again! */
|
||||
PASSWORD_MATCH_ERROR("password_error"),
|
||||
|
||||
/** You can't use your name as password, please choose another one... */
|
||||
PASSWORD_IS_USERNAME_ERROR("password_error_nick"),
|
||||
|
||||
/** The chosen password isn't safe, please choose another one... */
|
||||
PASSWORD_UNSAFE_ERROR("password_error_unsafe"),
|
||||
|
||||
/** Your password contains illegal characters. Allowed chars: REG_EX */
|
||||
PASSWORD_CHARACTERS_ERROR("password_error_chars", "REG_EX"),
|
||||
|
||||
/** Your IP has been changed and your session data has expired! */
|
||||
SESSION_EXPIRED("invalid_session"),
|
||||
|
||||
/** Only registered users can join the server! Please visit http://example.com to register yourself! */
|
||||
MUST_REGISTER_MESSAGE("reg_only"),
|
||||
|
||||
/** You're already logged in! */
|
||||
ALREADY_LOGGED_IN_ERROR("logged_in"),
|
||||
|
||||
/** Logged-out successfully! */
|
||||
LOGOUT_SUCCESS("logout"),
|
||||
|
||||
/** The same username is already playing on the server! */
|
||||
USERNAME_ALREADY_ONLINE_ERROR("same_nick"),
|
||||
|
||||
/** Successfully registered! */
|
||||
REGISTER_SUCCESS("registered"),
|
||||
|
||||
/** Your password is too short or too long! Please try with another one! */
|
||||
INVALID_PASSWORD_LENGTH("pass_len"),
|
||||
|
||||
/** Configuration and database have been reloaded correctly! */
|
||||
CONFIG_RELOAD_SUCCESS("reload"),
|
||||
|
||||
/** Login timeout exceeded, you have been kicked from the server, please try again! */
|
||||
LOGIN_TIMEOUT_ERROR("timeout"),
|
||||
|
||||
/** Usage: /changepassword >oldPassword> >newPassword> */
|
||||
USAGE_CHANGE_PASSWORD("usage_changepassword"),
|
||||
|
||||
/** Your username is either too short or too long! */
|
||||
INVALID_NAME_LENGTH("name_len"),
|
||||
|
||||
/** Your username contains illegal characters. Allowed chars: REG_EX */
|
||||
INVALID_NAME_CHARACTERS("regex", "REG_EX"),
|
||||
|
||||
/** Please add your email to your account with the command "/email add >yourEmail> >confirmEmail>" */
|
||||
ADD_EMAIL_MESSAGE("add_email"),
|
||||
|
||||
/** Forgot your password? Please use the command "/email recovery >yourEmail>" */
|
||||
FORGOT_PASSWORD_MESSAGE("recovery_email"),
|
||||
|
||||
/** To login you have to solve a captcha code, please use the command "/captcha >theCaptcha>" */
|
||||
USAGE_CAPTCHA("usage_captcha", "<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 >email> >confirmEmail> */
|
||||
USAGE_ADD_EMAIL("usage_email_add"),
|
||||
|
||||
/** Usage: /email change >oldEmail> >newEmail> */
|
||||
USAGE_CHANGE_EMAIL("usage_email_change"),
|
||||
|
||||
/** Usage: /email recovery >Email> */
|
||||
USAGE_RECOVER_EMAIL("usage_email_recovery"),
|
||||
|
||||
/** Invalid new email, try again! */
|
||||
INVALID_NEW_EMAIL("new_email_invalid"),
|
||||
|
||||
/** Invalid old email, try again! */
|
||||
INVALID_OLD_EMAIL("old_email_invalid"),
|
||||
|
||||
/** Invalid email address, try again! */
|
||||
INVALID_EMAIL("email_invalid"),
|
||||
|
||||
/** Email address successfully added to your account! */
|
||||
EMAIL_ADDED_SUCCESS("email_added"),
|
||||
|
||||
/** Please confirm your email address! */
|
||||
CONFIRM_EMAIL_MESSAGE("email_confirm"),
|
||||
|
||||
/** Email address changed correctly! */
|
||||
EMAIL_CHANGED_SUCCESS("email_changed"),
|
||||
|
||||
/** Your current email address is: %email */
|
||||
EMAIL_SHOW("email_show", "%email"),
|
||||
|
||||
/** You currently don't have email address associated with this account. */
|
||||
SHOW_NO_EMAIL("show_no_email"),
|
||||
|
||||
/** Recovery email sent successfully! Please check your email inbox! */
|
||||
RECOVERY_EMAIL_SENT_MESSAGE("email_send"),
|
||||
|
||||
/** A recovery email was already sent! You can discard it and send a new one using the command below: */
|
||||
RECOVERY_EMAIL_ALREADY_SENT_MESSAGE("email_exists"),
|
||||
|
||||
/** Your country is banned from this server! */
|
||||
COUNTRY_BANNED_ERROR("country_banned"),
|
||||
|
||||
/** [AntiBotService] AntiBot enabled due to the huge number of connections! */
|
||||
ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"),
|
||||
|
||||
/** [AntiBotService] AntiBot disabled after %m minutes! */
|
||||
ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"),
|
||||
|
||||
/** The email address is already being used */
|
||||
EMAIL_ALREADY_USED_ERROR("email_already_used"),
|
||||
|
||||
/** Your secret code is %code. You can scan it from here %url */
|
||||
TWO_FACTOR_CREATE("two_factor_create", "%code", "%url"),
|
||||
|
||||
/** You are not the owner of this account. Please choose another name! */
|
||||
NOT_OWNER_ERROR("not_owner_error"),
|
||||
|
||||
/** You should join using username %valid, not %invalid. */
|
||||
INVALID_NAME_CASE("invalid_name_case", "%valid", "%invalid"),
|
||||
|
||||
/** You have been temporarily banned for failing to log in too many times. */
|
||||
TEMPBAN_MAX_LOGINS("tempban_max_logins"),
|
||||
|
||||
/** You own %count accounts: */
|
||||
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
|
||||
|
||||
/** The player %name has %count accounts: */
|
||||
ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"),
|
||||
|
||||
/** An admin just registered you; please log in again */
|
||||
KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"),
|
||||
|
||||
/** Error: not all required settings are set for sending emails. Please contact an admin. */
|
||||
INCOMPLETE_EMAIL_SETTINGS("incomplete_email_settings"),
|
||||
|
||||
/** The email could not be sent. Please contact an administrator. */
|
||||
EMAIL_SEND_FAILURE("email_send_failure"),
|
||||
|
||||
/** A recovery code to reset your password has been sent to your email. */
|
||||
RECOVERY_CODE_SENT("recovery_code_sent"),
|
||||
|
||||
/** The recovery code is not correct! Use /email recovery [email] to generate a new one */
|
||||
INCORRECT_RECOVERY_CODE("recovery_code_incorrect");
|
||||
|
||||
private String key;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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 {
|
||||
|
||||
|
60
src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
Normal file
60
src/main/java/fr/xephi/authme/security/crypts/Pbkdf2.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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];
|
@ -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;
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
package fr.xephi.authme.security.pbkdf2;
|
||||
|
||||
/*
|
||||
* Free auxiliary functions. Copyright 2007, 2014, Matthias Gärtner
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Free auxiliary functions
|
||||
*
|
||||
* @author Matthias Gärtner
|
||||
*/
|
||||
public class BinTools {
|
||||
public static final String hex = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* Simple binary-to-hexadecimal conversion.
|
||||
*
|
||||
* @param b
|
||||
* Input bytes. May be <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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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ä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ä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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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ä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ä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);
|
||||
}
|
@ -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ä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ä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
|
||||
* "Salt:iteration-count:PBKDF2" with binary data in hexadecimal
|
||||
* encoding.
|
||||
* <p>
|
||||
* Example: Password "password" (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;
|
||||
}
|
||||
}
|
@ -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ä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ä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);
|
||||
}
|
@ -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ä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ä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;
|
||||
}
|
||||
}
|
@ -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ä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ä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;
|
||||
}
|
||||
}
|
@ -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ä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ä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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -40,7 +40,8 @@ public class ValidationService implements Reloadable {
|
||||
private Pattern passwordRegex;
|
||||
private Set<String> unrestrictedNames;
|
||||
|
||||
ValidationService() { }
|
||||
ValidationService() {
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@Override
|
||||
|
46
src/main/java/fr/xephi/authme/settings/EnumSetProperty.java
Normal file
46
src/main/java/fr/xephi/authme/settings/EnumSetProperty.java
Normal 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
Loading…
Reference in New Issue
Block a user