mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-14 14:25:24 +01:00
Merge branch 'master' of https://github.com/AuthMe/AuthMeReloaded into 1128-camel-case-rename
This commit is contained in:
commit
8ebb3c6b5a
164
.checkstyle.xml
Normal file
164
.checkstyle.xml
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||||
|
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||||
|
|
||||||
|
<module name="Checker">
|
||||||
|
<property name="charset" value="UTF-8"/>
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
<property name="fileExtensions" value="java, properties, xml"/>
|
||||||
|
|
||||||
|
<module name="SuppressWarningsFilter" />
|
||||||
|
|
||||||
|
<module name="TreeWalker">
|
||||||
|
<module name="SuppressWarningsHolder"/>
|
||||||
|
<module name="OuterTypeFilename"/>
|
||||||
|
<module name="IllegalTokenText">
|
||||||
|
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||||
|
<property name="format" value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||||
|
<property name="message" value="Avoid using corresponding octal or Unicode escape."/>
|
||||||
|
</module>
|
||||||
|
<module name="AvoidEscapedUnicodeCharacters">
|
||||||
|
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||||
|
<property name="allowByTailComment" value="true"/>
|
||||||
|
<property name="allowNonPrintableEscapes" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="LineLength">
|
||||||
|
<property name="max" value="120"/>
|
||||||
|
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||||
|
</module>
|
||||||
|
<module name="TodoComment">
|
||||||
|
<property name="format" value="TODO|FIXME"/>
|
||||||
|
</module>
|
||||||
|
<module name="GenericWhitespace"/>
|
||||||
|
<module name="AvoidStarImport"/>
|
||||||
|
<module name="RedundantImport"/>
|
||||||
|
<module name="UnusedImports"/>
|
||||||
|
<module name="OneTopLevelClass"/>
|
||||||
|
<module name="FinalClass"/>
|
||||||
|
<module name="HideUtilityClassConstructor"/>
|
||||||
|
<module name="InnerTypeLast"/>
|
||||||
|
<module name="VisibilityModifier"/>
|
||||||
|
<module name="AvoidNestedBlocks"/>
|
||||||
|
<module name="NoLineWrap"/>
|
||||||
|
<module name="EmptyBlock">
|
||||||
|
<property name="option" value="TEXT"/>
|
||||||
|
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||||
|
</module>
|
||||||
|
<module name="NeedBraces"/>
|
||||||
|
<module name="RightCurly"/>
|
||||||
|
<module name="RightCurly">
|
||||||
|
<property name="option" value="alone"/>
|
||||||
|
<property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
|
||||||
|
</module>
|
||||||
|
<module name="OneStatementPerLine"/>
|
||||||
|
<module name="MultipleVariableDeclarations"/>
|
||||||
|
<module name="ArrayTypeStyle"/>
|
||||||
|
<module name="MissingSwitchDefault"/>
|
||||||
|
<module name="FallThrough"/>
|
||||||
|
<module name="UpperEll"/>
|
||||||
|
<module name="ModifierOrder"/>
|
||||||
|
<module name="RedundantModifier"/>
|
||||||
|
<module name="EmptyLineSeparator">
|
||||||
|
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<property name="tokens" value="DOT"/>
|
||||||
|
<property name="option" value="nl"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<property name="tokens" value="COMMA"/>
|
||||||
|
<property name="option" value="EOL"/>
|
||||||
|
</module>
|
||||||
|
<module name="PackageName">
|
||||||
|
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="TypeName">
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="MemberName">
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="ParameterName">
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="LocalVariableName">
|
||||||
|
<property name="tokens" value="VARIABLE_DEF"/>
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||||
|
<property name="allowOneCharVarInForLoop" value="true"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="ClassTypeParameterName">
|
||||||
|
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="MethodTypeParameterName">
|
||||||
|
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="NoFinalizer"/>
|
||||||
|
<module name="AbbreviationAsWordInName">
|
||||||
|
<property name="ignoreFinal" value="false"/>
|
||||||
|
<property name="allowedAbbreviationLength" value="1"/>
|
||||||
|
</module>
|
||||||
|
<module name="OverloadMethodsDeclarationOrder"/>
|
||||||
|
<module name="VariableDeclarationUsageDistance"/>
|
||||||
|
<module name="MethodParamPad"/>
|
||||||
|
<module name="BooleanExpressionComplexity">
|
||||||
|
<property name="max" value="5"/>
|
||||||
|
</module>
|
||||||
|
<module name="OperatorWrap">
|
||||||
|
<property name="option" value="NL"/>
|
||||||
|
<property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
|
||||||
|
</module>
|
||||||
|
<module name="CyclomaticComplexity">
|
||||||
|
<property name="max" value="15"/>
|
||||||
|
</module>
|
||||||
|
<module name="JavaNCSS">
|
||||||
|
<property name="methodMaximum" value="40"/>
|
||||||
|
<property name="classMaximum" value="1000"/>
|
||||||
|
</module>
|
||||||
|
<module name="AnnotationLocation">
|
||||||
|
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
|
||||||
|
</module>
|
||||||
|
<module name="AnnotationLocation">
|
||||||
|
<property name="tokens" value="VARIABLE_DEF"/>
|
||||||
|
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="NonEmptyAtclauseDescription"/>
|
||||||
|
<module name="JavadocTagContinuationIndentation"/>
|
||||||
|
<module name="AtclauseOrder">
|
||||||
|
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||||
|
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||||
|
</module>
|
||||||
|
<module name="JavadocMethod">
|
||||||
|
<property name="scope" value="package"/>
|
||||||
|
<property name="allowMissingThrowsTags" value="true"/>
|
||||||
|
<property name="minLineCount" value="4"/>
|
||||||
|
<property name="allowedAnnotations" value="Override, Test"/>
|
||||||
|
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/>
|
||||||
|
</module>
|
||||||
|
<module name="MethodName">
|
||||||
|
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="SingleLineJavadoc">
|
||||||
|
<property name="ignoredTags" value="@return"/>
|
||||||
|
</module>
|
||||||
|
<module name="EmptyCatchBlock">
|
||||||
|
<property name="exceptionVariableName" value="ignore|ignored"/>
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
|
<module name="FileTabCharacter"/>
|
||||||
|
</module>
|
30
.codeclimate.yml
Normal file
30
.codeclimate.yml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
engines:
|
||||||
|
duplication:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
languages:
|
||||||
|
- java
|
||||||
|
- php
|
||||||
|
checkstyle:
|
||||||
|
enabled: true
|
||||||
|
channel: beta
|
||||||
|
config: '.checkstyle.xml'
|
||||||
|
pmd:
|
||||||
|
enabled: true
|
||||||
|
channel: beta
|
||||||
|
checks:
|
||||||
|
AvoidUsingHardCodedIP:
|
||||||
|
enabled: false
|
||||||
|
ratings:
|
||||||
|
paths:
|
||||||
|
# Check only production files
|
||||||
|
- 'src/main/java/**'
|
||||||
|
exclude_paths:
|
||||||
|
# Exclude code from third-party sources
|
||||||
|
- 'src/main/java/fr/xephi/authme/mail/OAuth2Provider.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/mail/OAuth2SaslClient.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/mail/OAuth2SaslClientFactory.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/security/crypts/BCryptService.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/security/crypts/PHPBB.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java'
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
### Java files ###
|
### Java files ###
|
||||||
*.class
|
*.class
|
||||||
|
MANIFEST.MF
|
||||||
|
|
||||||
# Package Files
|
# Package Files
|
||||||
#*.jar
|
#*.jar
|
||||||
|
14
README.md
14
README.md
@ -19,20 +19,14 @@
|
|||||||
- Project status:
|
- Project status:
|
||||||
- Dependencies: [![Dependencies status](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d/badge.svg)](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
|
- 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)
|
- 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)
|
||||||
|
- Code climate: [![Code Climate](https://codeclimate.com/github/AuthMe/AuthMeReloaded/badges/gpa.svg)](https://codeclimate.com/github/AuthMe/AuthMeReloaded)
|
||||||
|
|
||||||
- Development resources:
|
- Development resources:
|
||||||
- <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">JavaDocs</a>
|
- <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">JavaDocs</a>
|
||||||
- <a href="http://ci.xephi.fr/plugin/repository/everything/">Maven Repository</a>
|
- <a href="http://ci.xephi.fr/plugin/repository/everything/">Maven Repository</a>
|
||||||
|
|
||||||
#####Statistics:
|
- Statistics:
|
||||||
|
- bStats: [AuthMe on bstats.org](https://bstats.org/plugin/bukkit/AuthMe)
|
||||||
McStats: http://mcstats.org/plugin/AuthMe
|
|
||||||
|
|
||||||
<img src="http://i.mcstats.org/AuthMe/Global+Statistics.borderless.png">
|
|
||||||
|
|
||||||
<img src="http://i.mcstats.org/AuthMe/Rank.borderless.png">
|
|
||||||
|
|
||||||
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
@ -92,7 +86,7 @@ You can also create your own translation file and, if you want, you can share it
|
|||||||
<li>DoubleSaltedMD5: SALTED2MD5</li>
|
<li>DoubleSaltedMD5: SALTED2MD5</li>
|
||||||
<li>WordPress: WORDPRESS</li>
|
<li>WordPress: WORDPRESS</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li>Custom MySQL tables/columns names (useful with forums databases)</li>
|
<li>Custom MySQL tables/columns names (useful with forum databases)</li>
|
||||||
<li><strong>Cached database queries!</strong></li>
|
<li><strong>Cached database queries!</strong></li>
|
||||||
<li><strong>Fully compatible with Citizens2, CombatTag, CombatTagPlus!</strong></li>
|
<li><strong>Fully compatible with Citizens2, CombatTag, CombatTagPlus!</strong></li>
|
||||||
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
|
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Sat Jan 14 22:12:16 CET 2017. See docs/config/config.tpl.md -->
|
<!-- File auto-generated on Sat Feb 25 21:59:18 CET 2017. See docs/config/config.tpl.md -->
|
||||||
|
|
||||||
## AuthMe Configuration
|
## AuthMe Configuration
|
||||||
The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
|
The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
|
||||||
@ -18,9 +18,11 @@ DataSource:
|
|||||||
mySQLHost: '127.0.0.1'
|
mySQLHost: '127.0.0.1'
|
||||||
# Database port
|
# Database port
|
||||||
mySQLPort: '3306'
|
mySQLPort: '3306'
|
||||||
# Username about Database Connection Infos
|
# Connect to MySQL database over SSL
|
||||||
|
mySQLUseSSL: true
|
||||||
|
# Username to connect to the MySQL database
|
||||||
mySQLUsername: 'authme'
|
mySQLUsername: 'authme'
|
||||||
# Password about Database Connection Infos
|
# Password to connect to the MySQL database
|
||||||
mySQLPassword: '12345'
|
mySQLPassword: '12345'
|
||||||
# Database Name, use with converters or as SQLITE database name
|
# Database Name, use with converters or as SQLITE database name
|
||||||
mySQLDatabase: 'authme'
|
mySQLDatabase: 'authme'
|
||||||
@ -34,8 +36,6 @@ DataSource:
|
|||||||
mySQLRealName: 'realname'
|
mySQLRealName: 'realname'
|
||||||
# Column for storing players passwords
|
# Column for storing players passwords
|
||||||
mySQLColumnPassword: 'password'
|
mySQLColumnPassword: 'password'
|
||||||
# Request mysql over SSL
|
|
||||||
mySQLUseSSL: true
|
|
||||||
# Column for storing players emails
|
# Column for storing players emails
|
||||||
mySQLColumnEmail: 'email'
|
mySQLColumnEmail: 'email'
|
||||||
# Column for storing if a player is logged in or not
|
# Column for storing if a player is logged in or not
|
||||||
@ -94,13 +94,8 @@ settings:
|
|||||||
# expired, he will not need to authenticate.
|
# expired, he will not need to authenticate.
|
||||||
enabled: false
|
enabled: false
|
||||||
# After how many minutes should a session expire?
|
# After how many minutes should a session expire?
|
||||||
# Remember that sessions will end only after the timeout, and
|
# A player's session ends after the timeout or if his IP has changed
|
||||||
# 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
|
timeout: 10
|
||||||
# Should the session expire if the player tries to log in with
|
|
||||||
# another IP address?
|
|
||||||
sessionExpireOnIpChange: true
|
|
||||||
# Message language, available languages:
|
# Message language, available languages:
|
||||||
# https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md
|
# https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md
|
||||||
messagesLanguage: 'en'
|
messagesLanguage: 'en'
|
||||||
@ -161,6 +156,8 @@ settings:
|
|||||||
# AllowedRestrictedUser:
|
# AllowedRestrictedUser:
|
||||||
# - playername;127.0.0.1
|
# - playername;127.0.0.1
|
||||||
AllowedRestrictedUser: []
|
AllowedRestrictedUser: []
|
||||||
|
# Ban unknown IPs trying to log in with a restricted username?
|
||||||
|
banUnsafedIP: false
|
||||||
# Should unregistered players be kicked immediately?
|
# Should unregistered players be kicked immediately?
|
||||||
kickNonRegistered: false
|
kickNonRegistered: false
|
||||||
# Should players be kicked on wrong password?
|
# Should players be kicked on wrong password?
|
||||||
@ -177,7 +174,7 @@ settings:
|
|||||||
# After how many seconds should players who fail to login or register
|
# After how many seconds should players who fail to login or register
|
||||||
# be kicked? Set to 0 to disable.
|
# be kicked? Set to 0 to disable.
|
||||||
timeout: 30
|
timeout: 30
|
||||||
# Regex syntax of allowed characters in the player name.
|
# Regex pattern of allowed characters in the player name.
|
||||||
allowedNicknameCharacters: '[a-zA-Z0-9_]*'
|
allowedNicknameCharacters: '[a-zA-Z0-9_]*'
|
||||||
# How far can unregistered players walk?
|
# How far can unregistered players walk?
|
||||||
# Set to 0 for unlimited radius
|
# Set to 0 for unlimited radius
|
||||||
@ -189,8 +186,6 @@ settings:
|
|||||||
# Should we display all other accounts from a player when he joins?
|
# Should we display all other accounts from a player when he joins?
|
||||||
# permission: /authme.admin.accounts
|
# permission: /authme.admin.accounts
|
||||||
displayOtherAccounts: true
|
displayOtherAccounts: true
|
||||||
# Ban ip when the ip is not the ip registered in database
|
|
||||||
banUnsafedIP: false
|
|
||||||
# Spawn priority; values: authme, essentials, multiverse, default
|
# Spawn priority; values: authme, essentials, multiverse, default
|
||||||
spawnPriority: 'authme,essentials,multiverse,default'
|
spawnPriority: 'authme,essentials,multiverse,default'
|
||||||
# Maximum Login authorized by IP
|
# Maximum Login authorized by IP
|
||||||
@ -223,18 +218,6 @@ settings:
|
|||||||
minPasswordLength: 5
|
minPasswordLength: 5
|
||||||
# Maximum length of password
|
# Maximum length of password
|
||||||
passwordMaxLength: 30
|
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: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,
|
# Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,
|
||||||
# MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,
|
# MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,
|
||||||
# PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only). See full list at
|
# PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only). See full list at
|
||||||
@ -317,12 +300,24 @@ settings:
|
|||||||
# Do we need to prevent people to login with another case?
|
# Do we need to prevent people to login with another case?
|
||||||
# If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
|
# If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
|
||||||
preventOtherCase: true
|
preventOtherCase: true
|
||||||
permission:
|
GroupOptions:
|
||||||
# Take care with this option; if you want
|
# Enables switching a player to defined permission groups before they log in.
|
||||||
# to use group switching of AuthMe
|
# See below for a detailed explanation.
|
||||||
# for unloggedIn players, set this setting to true.
|
enablePermissionCheck: false
|
||||||
# Default is false.
|
# This is a very important option: if a registered player joins the server
|
||||||
EnablePermissionCheck: false
|
# 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 login, the 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: registeredPlayerGroup: 'NotLogged'
|
||||||
|
registeredPlayerGroup: ''
|
||||||
|
# Similar to above, unregistered players can be set to the following
|
||||||
|
# permissions group
|
||||||
|
unregisteredPlayerGroup: ''
|
||||||
Email:
|
Email:
|
||||||
# Email SMTP server host
|
# Email SMTP server host
|
||||||
mailSMTP: 'smtp.gmail.com'
|
mailSMTP: 'smtp.gmail.com'
|
||||||
@ -366,18 +361,13 @@ Hooks:
|
|||||||
disableSocialSpy: false
|
disableSocialSpy: false
|
||||||
# Do we need to force /motd Essentials command on join?
|
# Do we need to force /motd Essentials command on join?
|
||||||
useEssentialsMotd: false
|
useEssentialsMotd: false
|
||||||
GroupOptions:
|
|
||||||
# Unregistered permission group
|
|
||||||
UnregisteredPlayerGroup: ''
|
|
||||||
# Registered permission group
|
|
||||||
RegisteredPlayerGroup: ''
|
|
||||||
Protection:
|
Protection:
|
||||||
# Enable some servers protection (country based login, antibot)
|
# Enable some servers protection (country based login, antibot)
|
||||||
enableProtection: false
|
enableProtection: false
|
||||||
# Apply the protection also to registered usernames
|
# Apply the protection also to registered usernames
|
||||||
enableProtectionRegistered: true
|
enableProtectionRegistered: true
|
||||||
# Countries allowed to join the server and register. For country codes, see
|
# Countries allowed to join the server and register. For country codes, see
|
||||||
# http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/
|
# https://dev.bukkit.org/projects/authme-reloaded/pages/countries-codes
|
||||||
# PLEASE USE QUOTES!
|
# PLEASE USE QUOTES!
|
||||||
countries:
|
countries:
|
||||||
- 'US'
|
- 'US'
|
||||||
@ -432,6 +422,8 @@ Security:
|
|||||||
maxLoginTry: 5
|
maxLoginTry: 5
|
||||||
# Captcha length
|
# Captcha length
|
||||||
captchaLength: 5
|
captchaLength: 5
|
||||||
|
# Minutes after which login attempts count is reset for a player
|
||||||
|
captchaCountReset: 60
|
||||||
tempban:
|
tempban:
|
||||||
# Tempban a user's IP address if they enter the wrong password too many times
|
# Tempban a user's IP address if they enter the wrong password too many times
|
||||||
enableTempban: false
|
enableTempban: false
|
||||||
@ -448,6 +440,10 @@ Security:
|
|||||||
length: 8
|
length: 8
|
||||||
# How many hours is a recovery code valid for?
|
# How many hours is a recovery code valid for?
|
||||||
validForHours: 4
|
validForHours: 4
|
||||||
|
emailRecovery:
|
||||||
|
# Seconds a user has to wait for before a password recovery mail may be sent again
|
||||||
|
# This prevents an attacker from abusing AuthMe's email feature.
|
||||||
|
cooldown: 60
|
||||||
BackupSystem:
|
BackupSystem:
|
||||||
# Enable or disable automatic backup
|
# Enable or disable automatic backup
|
||||||
ActivateBackup: false
|
ActivateBackup: false
|
||||||
@ -464,4 +460,4 @@ To change settings on a running server, save your changes to config.yml and use
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Jan 14 22:12:16 CET 2017
|
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Feb 25 21:59:18 CET 2017
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Wed Jan 11 21:24:50 CET 2017. See docs/translations/translations.tpl.md -->
|
<!-- File auto-generated on Mon Mar 13 20:34:31 CET 2017. See docs/translations/translations.tpl.md -->
|
||||||
|
|
||||||
# AuthMe Translations
|
# AuthMe Translations
|
||||||
The following translations are available in AuthMe. Set `messagesLanguage` to the language code
|
The following translations are available in AuthMe. Set `messagesLanguage` to the language code
|
||||||
@ -8,35 +8,34 @@ in your config.yml to use the language, or use another language code to start a
|
|||||||
Code | Language | Translated |
|
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" />
|
[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 | 69% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=69&h=5&txtpad=1" alt="bar" />
|
[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&h=5&txtpad=1" alt="bar" />
|
||||||
[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&h=5&txtpad=1" alt="bar" />
|
||||||
[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&h=5&txtpad=1" alt="bar" />
|
||||||
[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 62% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=62&h=5&txtpad=1" alt="bar" />
|
[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 55% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb6600&w=55&h=5&txtpad=1" alt="bar" />
|
||||||
[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 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 | 59% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=59&h=5&txtpad=1" alt="bar" />
|
||||||
[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 70% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=70&h=5&txtpad=1" alt="bar" />
|
[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 63% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=63&h=5&txtpad=1" alt="bar" />
|
||||||
[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 99% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=99&h=5&txtpad=1" alt="bar" />
|
[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&h=5&txtpad=1" alt="bar" />
|
||||||
[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 70% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=70&h=5&txtpad=1" alt="bar" />
|
[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 63% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=63&h=5&txtpad=1" alt="bar" />
|
||||||
[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&h=5&txtpad=1" alt="bar" />
|
[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 64% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=64&h=5&txtpad=1" alt="bar" />
|
||||||
[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Lithuanian | 53% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb6600&w=53&h=5&txtpad=1" alt="bar" />
|
[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Lithuanian | 47% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa5500&w=47&h=5&txtpad=1" alt="bar" />
|
||||||
[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 77% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb9900&w=77&h=5&txtpad=1" alt="bar" />
|
[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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" />
|
[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 | 86% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=86&h=5&txtpad=1" alt="bar" />
|
[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 99% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=99&h=5&txtpad=1" alt="bar" />
|
[ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&h=5&txtpad=1" alt="bar" />
|
||||||
[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 99% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=99&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 | 46% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa5500&w=46&h=5&txtpad=1" alt="bar" />
|
[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 41% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa4400&w=41&h=5&txtpad=1" alt="bar" />
|
||||||
[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 81% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=81&h=5&txtpad=1" alt="bar" />
|
[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
||||||
[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 93% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=77dd44&w=93&h=5&txtpad=1" alt="bar" />
|
[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
|
||||||
[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&h=5&txtpad=1" alt="bar" />
|
||||||
[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 81% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=81&h=5&txtpad=1" alt="bar" />
|
[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&h=5&txtpad=1" alt="bar" />
|
||||||
[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 81% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=81&h=5&txtpad=1" alt="bar" />
|
[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&h=5&txtpad=1" alt="bar" />
|
||||||
[zhmc](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhmc.yml) | Chinese (Macau) | 96% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ee55&w=96&h=5&txtpad=1" alt="bar" />
|
[zhmc](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhmc.yml) | Chinese (Macau) | 86% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=99bb22&w=86&h=5&txtpad=1" alt="bar" />
|
||||||
[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 81% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=81&h=5&txtpad=1" alt="bar" />
|
[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&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 Wed Jan 11 21:24:50 CET 2017
|
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Mon Mar 13 20:34:31 CET 2017
|
||||||
|
58
pom.xml
58
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>fr.xephi</groupId>
|
<groupId>fr.xephi</groupId>
|
||||||
<artifactId>authme</artifactId>
|
<artifactId>authme</artifactId>
|
||||||
<version>5.2</version>
|
<version>5.3-SNAPSHOT</version>
|
||||||
|
|
||||||
<name>AuthMeReloaded</name>
|
<name>AuthMeReloaded</name>
|
||||||
<description>The first authentication plugin for the Bukkit API!</description>
|
<description>The first authentication plugin for the Bukkit API!</description>
|
||||||
@ -108,10 +108,6 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
|
||||||
<artifactId>json-simple</artifactId>
|
|
||||||
<groupId>com.googlecode.json-simple</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<artifactId>persistence-api</artifactId>
|
<artifactId>persistence-api</artifactId>
|
||||||
<groupId>javax.persistence</groupId>
|
<groupId>javax.persistence</groupId>
|
||||||
@ -146,10 +142,6 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
|
||||||
<artifactId>json-simple</artifactId>
|
|
||||||
<groupId>com.googlecode.json-simple</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<artifactId>persistence-api</artifactId>
|
<artifactId>persistence-api</artifactId>
|
||||||
<groupId>javax.persistence</groupId>
|
<groupId>javax.persistence</groupId>
|
||||||
@ -249,8 +241,8 @@
|
|||||||
<shadedPattern>fr.xephi.authme.libs.jalu.injector</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.jalu.injector</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.github.authme.configme</pattern>
|
<pattern>ch.jalu.configme</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.authme.configme</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.jalu.configme</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.zaxxer.hikari</pattern>
|
<pattern>com.zaxxer.hikari</pattern>
|
||||||
@ -276,10 +268,10 @@
|
|||||||
<pattern>javax.inject</pattern>
|
<pattern>javax.inject</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<!-- MCStats.org metrics -->
|
<!-- bStats metrics class -->
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>org.mcstats</pattern>
|
<pattern>org.bstats</pattern>
|
||||||
<shadedPattern>fr.xephi.authme</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.org.bstats</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<outputFile>target/${project.finalName}-spigot.jar</outputFile>
|
<outputFile>target/${project.finalName}-spigot.jar</outputFile>
|
||||||
@ -331,10 +323,10 @@
|
|||||||
<pattern>javax.inject</pattern>
|
<pattern>javax.inject</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<!-- MCStats.org metrics -->
|
<!-- bStats metrics class -->
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>org.mcstats</pattern>
|
<pattern>org.bstats</pattern>
|
||||||
<shadedPattern>fr.xephi.authme</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.org.bstats</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<outputFile>target/${project.finalName}-legacy.jar</outputFile>
|
<outputFile>target/${project.finalName}-legacy.jar</outputFile>
|
||||||
@ -442,6 +434,12 @@
|
|||||||
<id>xephi-repo</id>
|
<id>xephi-repo</id>
|
||||||
<url>http://ci.xephi.fr/plugin/repository/everything/</url>
|
<url>http://ci.xephi.fr/plugin/repository/everything/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
|
<!-- bStats Repo -->
|
||||||
|
<repository>
|
||||||
|
<id>bstats-repo</id>
|
||||||
|
<url>http://repo.bstats.org/content/groups/public</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -451,7 +449,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.jalu</groupId>
|
<groupId>ch.jalu</groupId>
|
||||||
<artifactId>injector</artifactId>
|
<artifactId>injector</artifactId>
|
||||||
<version>0.3</version>
|
<version>0.4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -513,7 +511,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
<version>2.5.1</version>
|
<version>2.6.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
@ -527,7 +525,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
<version>1.7.21</version>
|
<version>1.7.22</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -544,19 +542,11 @@
|
|||||||
|
|
||||||
<!-- Bukkit Libraries -->
|
<!-- Bukkit Libraries -->
|
||||||
|
|
||||||
<!-- Metrics API -->
|
<!-- bStats metrics -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mcstats.bukkit</groupId>
|
<groupId>org.bstats</groupId>
|
||||||
<artifactId>metrics</artifactId>
|
<artifactId>bstats-bukkit</artifactId>
|
||||||
<version>R8-SNAPSHOT</version>
|
<version>1.0</version>
|
||||||
<scope>compile</scope>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.bukkit</groupId>
|
|
||||||
<artifactId>bukkit</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- ProtocolLib -->
|
<!-- ProtocolLib -->
|
||||||
@ -902,7 +892,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.jalu</groupId>
|
<groupId>ch.jalu</groupId>
|
||||||
<artifactId>configme</artifactId>
|
<artifactId>configme</artifactId>
|
||||||
<version>0.3</version>
|
<version>0.4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
@ -933,7 +923,7 @@
|
|||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
<version>2.4.1</version>
|
<version>2.7.9</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<artifactId>hamcrest-core</artifactId>
|
<artifactId>hamcrest-core</artifactId>
|
||||||
|
@ -14,6 +14,7 @@ import fr.xephi.authme.initialization.OnShutdownPlayerSaver;
|
|||||||
import fr.xephi.authme.initialization.OnStartupTasks;
|
import fr.xephi.authme.initialization.OnStartupTasks;
|
||||||
import fr.xephi.authme.initialization.SettingsProvider;
|
import fr.xephi.authme.initialization.SettingsProvider;
|
||||||
import fr.xephi.authme.initialization.TaskCloser;
|
import fr.xephi.authme.initialization.TaskCloser;
|
||||||
|
import fr.xephi.authme.initialization.factory.FactoryDependencyHandler;
|
||||||
import fr.xephi.authme.listener.BlockListener;
|
import fr.xephi.authme.listener.BlockListener;
|
||||||
import fr.xephi.authme.listener.EntityListener;
|
import fr.xephi.authme.listener.EntityListener;
|
||||||
import fr.xephi.authme.listener.PlayerListener;
|
import fr.xephi.authme.listener.PlayerListener;
|
||||||
@ -27,19 +28,18 @@ import fr.xephi.authme.permission.PermissionsSystemType;
|
|||||||
import fr.xephi.authme.security.crypts.Sha256;
|
import fr.xephi.authme.security.crypts.Sha256;
|
||||||
import fr.xephi.authme.service.BackupService;
|
import fr.xephi.authme.service.BackupService;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.GeoIpService;
|
|
||||||
import fr.xephi.authme.service.MigrationService;
|
import fr.xephi.authme.service.MigrationService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.task.CleanupTask;
|
import fr.xephi.authme.task.CleanupTask;
|
||||||
import fr.xephi.authme.task.purge.PurgeService;
|
import fr.xephi.authme.task.purge.PurgeService;
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import org.apache.commons.lang.SystemUtils;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.PluginDescriptionFile;
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
@ -72,8 +72,6 @@ public class AuthMe extends JavaPlugin {
|
|||||||
private DataSource database;
|
private DataSource database;
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
private Injector injector;
|
private Injector injector;
|
||||||
private GeoIpService geoIpService;
|
|
||||||
private PlayerCache playerCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -139,6 +137,7 @@ public class AuthMe extends JavaPlugin {
|
|||||||
initialize();
|
initialize();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ConsoleLogger.logException("Aborting initialization of AuthMe:", e);
|
ConsoleLogger.logException("Aborting initialization of AuthMe:", e);
|
||||||
|
OnStartupTasks.displayLegacyJarHint(e);
|
||||||
stopOrUnload();
|
stopOrUnload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -197,11 +196,19 @@ public class AuthMe extends JavaPlugin {
|
|||||||
ConsoleLogger.setLogger(getLogger());
|
ConsoleLogger.setLogger(getLogger());
|
||||||
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
|
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
|
||||||
|
|
||||||
|
// Check java version
|
||||||
|
if(!SystemUtils.isJavaVersionAtLeast(1.8f)) {
|
||||||
|
throw new IllegalStateException("You need Java 1.8 or above to run this plugin!");
|
||||||
|
}
|
||||||
|
|
||||||
// Create plugin folder
|
// Create plugin folder
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
|
|
||||||
// Create injector, provide elements from the Bukkit environment and register providers
|
// Create injector, provide elements from the Bukkit environment and register providers
|
||||||
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
|
injector = new InjectorBuilder()
|
||||||
|
.addHandlers(new FactoryDependencyHandler())
|
||||||
|
.addDefaultHandlers("fr.xephi.authme")
|
||||||
|
.create();
|
||||||
injector.register(AuthMe.class, this);
|
injector.register(AuthMe.class, this);
|
||||||
injector.register(Server.class, getServer());
|
injector.register(Server.class, getServer());
|
||||||
injector.register(PluginManager.class, getServer().getPluginManager());
|
injector.register(PluginManager.class, getServer().getPluginManager());
|
||||||
@ -242,14 +249,13 @@ public class AuthMe extends JavaPlugin {
|
|||||||
*/
|
*/
|
||||||
protected void instantiateServices(Injector injector) {
|
protected void instantiateServices(Injector injector) {
|
||||||
// PlayerCache is still injected statically sometimes
|
// PlayerCache is still injected statically sometimes
|
||||||
playerCache = PlayerCache.getInstance();
|
PlayerCache playerCache = PlayerCache.getInstance();
|
||||||
injector.register(PlayerCache.class, playerCache);
|
injector.register(PlayerCache.class, playerCache);
|
||||||
|
|
||||||
database = injector.getSingleton(DataSource.class);
|
database = injector.getSingleton(DataSource.class);
|
||||||
permsMan = injector.getSingleton(PermissionsManager.class);
|
permsMan = injector.getSingleton(PermissionsManager.class);
|
||||||
bukkitService = injector.getSingleton(BukkitService.class);
|
bukkitService = injector.getSingleton(BukkitService.class);
|
||||||
commandHandler = injector.getSingleton(CommandHandler.class);
|
commandHandler = injector.getSingleton(CommandHandler.class);
|
||||||
geoIpService = injector.getSingleton(GeoIpService.class);
|
|
||||||
|
|
||||||
// Trigger construction of API classes; they will keep track of the singleton
|
// Trigger construction of API classes; they will keep track of the singleton
|
||||||
injector.getSingleton(NewAPI.class);
|
injector.getSingleton(NewAPI.class);
|
||||||
@ -270,6 +276,12 @@ public class AuthMe extends JavaPlugin {
|
|||||||
&& settings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
&& settings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
||||||
ConsoleLogger.warning("WARNING!!! You set session timeout to 0, this may cause security issues!");
|
ConsoleLogger.warning("WARNING!!! You set session timeout to 0, this may cause security issues!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use TLS property only affects port 25
|
||||||
|
if (!settings.getProperty(EmailSettings.PORT25_USE_TLS)
|
||||||
|
&& settings.getProperty(EmailSettings.SMTP_PORT) != 25) {
|
||||||
|
ConsoleLogger.warning("Note: You have set Email.useTls to false but this only affects mail over port 25");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -344,24 +356,6 @@ public class AuthMe extends JavaPlugin {
|
|||||||
ConsoleLogger.close();
|
ConsoleLogger.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String replaceAllInfo(String message, Player player) {
|
|
||||||
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
|
|
||||||
String ipAddress = PlayerUtils.getPlayerIp(player);
|
|
||||||
Server server = getServer();
|
|
||||||
return message
|
|
||||||
.replace("&", "\u00a7")
|
|
||||||
.replace("{PLAYER}", player.getName())
|
|
||||||
.replace("{ONLINE}", playersOnline)
|
|
||||||
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
|
|
||||||
.replace("{IP}", ipAddress)
|
|
||||||
.replace("{LOGINS}", Integer.toString(playerCache.getLogged()))
|
|
||||||
.replace("{WORLD}", player.getWorld().getName())
|
|
||||||
.replace("{SERVER}", server.getServerName())
|
|
||||||
.replace("{VERSION}", server.getBukkitVersion())
|
|
||||||
// TODO: We should cache info like this, maybe with a class that extends Player?
|
|
||||||
.replace("{COUNTRY}", geoIpService.getCountryName(ipAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Bukkit commands.
|
* Handle Bukkit commands.
|
||||||
*
|
*
|
||||||
|
@ -12,7 +12,10 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,6 +92,18 @@ public final class ConsoleLogger {
|
|||||||
writeLog("[WARN] " + message);
|
writeLog("[WARN] " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a Throwable with the provided message on WARNING level
|
||||||
|
* and save the stack trace to the log file.
|
||||||
|
*
|
||||||
|
* @param message The message to accompany the exception
|
||||||
|
* @param th The Throwable to log
|
||||||
|
*/
|
||||||
|
public static void logException(String message, Throwable th) {
|
||||||
|
warning(message + " " + StringUtils.formatException(th));
|
||||||
|
writeLog(Throwables.getStackTraceAsString(th));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log an INFO message.
|
* Log an INFO message.
|
||||||
*
|
*
|
||||||
@ -114,6 +129,10 @@ public final class ConsoleLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
// Debug log methods
|
||||||
|
// --------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a DEBUG message if enabled.
|
* Log a DEBUG message if enabled.
|
||||||
* <p>
|
* <p>
|
||||||
@ -124,21 +143,78 @@ public final class ConsoleLogger {
|
|||||||
*/
|
*/
|
||||||
public static void debug(String message) {
|
public static void debug(String message) {
|
||||||
if (logLevel.includes(LogLevel.DEBUG)) {
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
logger.info("Debug: " + message);
|
String debugMessage = "[DEBUG] " + message;
|
||||||
writeLog("[DEBUG] " + message);
|
logger.info(debugMessage);
|
||||||
|
writeLog(debugMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a Throwable with the provided message on WARNING level
|
* Log the DEBUG message from the supplier if enabled.
|
||||||
* and save the stack trace to the log file.
|
|
||||||
*
|
*
|
||||||
* @param message The message to accompany the exception
|
* @param msgSupplier the message supplier
|
||||||
* @param th The Throwable to log
|
|
||||||
*/
|
*/
|
||||||
public static void logException(String message, Throwable th) {
|
public static void debug(Supplier<String> msgSupplier) {
|
||||||
warning(message + " " + StringUtils.formatException(th));
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
writeLog(Throwables.getStackTraceAsString(th));
|
String debugMessage = "[DEBUG] " + msgSupplier.get();
|
||||||
|
logger.info(debugMessage);
|
||||||
|
writeLog(debugMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DEBUG message.
|
||||||
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param param1 parameter to replace in the message
|
||||||
|
*/
|
||||||
|
public static void debug(String message, String param1) {
|
||||||
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
|
String debugMessage = "[DEBUG] " + message;
|
||||||
|
logger.log(Level.INFO, debugMessage, param1);
|
||||||
|
writeLog(debugMessage + " {" + param1 + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DEBUG message.
|
||||||
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param param1 first param to replace in message
|
||||||
|
* @param param2 second param to replace in message
|
||||||
|
*/
|
||||||
|
// Avoids array creation if DEBUG level is disabled
|
||||||
|
public static void debug(String message, String param1, String param2) {
|
||||||
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
|
debug(message, new String[]{param1, param2});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DEBUG message.
|
||||||
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param params the params to replace in the message
|
||||||
|
*/
|
||||||
|
// Equivalent to debug(String, Object...) but avoids conversions
|
||||||
|
public static void debug(String message, String... params) {
|
||||||
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
|
String debugMessage = "[DEBUG] " + message;
|
||||||
|
logger.log(Level.INFO, debugMessage, params);
|
||||||
|
writeLog(debugMessage + " {" + String.join(", ", params) + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the DEBUG message.
|
||||||
|
*
|
||||||
|
* @param message the message
|
||||||
|
* @param params the params to replace in the message
|
||||||
|
*/
|
||||||
|
public static void debug(String message, Object... params) {
|
||||||
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
|
debug(message, Arrays.stream(params).map(String::valueOf).toArray(String[]::new));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import javax.inject.Inject;
|
|||||||
* @deprecated Use {@link NewAPI}
|
* @deprecated Use {@link NewAPI}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore
|
||||||
public class API {
|
public class API {
|
||||||
|
|
||||||
private static AuthMe instance;
|
private static AuthMe instance;
|
||||||
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
* NewAPI authmeApi = AuthMe.getApi();
|
* NewAPI authmeApi = AuthMe.getApi();
|
||||||
* </code>
|
* </code>
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore
|
||||||
public class NewAPI {
|
public class NewAPI {
|
||||||
|
|
||||||
private static NewAPI singleton;
|
private static NewAPI singleton;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.xephi.authme.command;
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
import fr.xephi.authme.permission.PermissionNode;
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,6 +19,7 @@ import static java.util.Arrays.asList;
|
|||||||
* {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that
|
* {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that
|
||||||
* the child defines.
|
* the child defines.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:FinalClass") // Justification: class is mocked in multiple tests
|
||||||
public class CommandDescription {
|
public class CommandDescription {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +225,7 @@ public class CommandDescription {
|
|||||||
* @return The generated CommandDescription object
|
* @return The generated CommandDescription object
|
||||||
*/
|
*/
|
||||||
public CommandDescription build() {
|
public CommandDescription build() {
|
||||||
checkArgument(!CollectionUtils.isEmpty(labels), "Labels may not be empty");
|
checkArgument(!Utils.isCollectionEmpty(labels), "Labels may not be empty");
|
||||||
checkArgument(!StringUtils.isEmpty(description), "Description may not be empty");
|
checkArgument(!StringUtils.isEmpty(description), "Description may not be empty");
|
||||||
checkArgument(!StringUtils.isEmpty(detailedDescription), "Detailed description may not be empty");
|
checkArgument(!StringUtils.isEmpty(detailedDescription), "Detailed description may not be empty");
|
||||||
checkArgument(executableCommand != null, "Executable command must be set");
|
checkArgument(executableCommand != null, "Executable command must be set");
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.xephi.authme.command;
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
import ch.jalu.injector.Injector;
|
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
|
import fr.xephi.authme.initialization.factory.Factory;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
@ -40,13 +40,13 @@ public class CommandHandler {
|
|||||||
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
|
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CommandHandler(Injector injector, CommandMapper commandMapper, PermissionsManager permissionsManager,
|
CommandHandler(Factory<ExecutableCommand> commandFactory, CommandMapper commandMapper,
|
||||||
Messages messages, HelpProvider helpProvider) {
|
PermissionsManager permissionsManager, Messages messages, HelpProvider helpProvider) {
|
||||||
this.commandMapper = commandMapper;
|
this.commandMapper = commandMapper;
|
||||||
this.permissionsManager = permissionsManager;
|
this.permissionsManager = permissionsManager;
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
this.helpProvider = helpProvider;
|
this.helpProvider = helpProvider;
|
||||||
initializeCommands(injector, commandMapper.getCommandClasses());
|
initializeCommands(commandFactory, commandMapper.getCommandClasses());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,13 +94,13 @@ public class CommandHandler {
|
|||||||
/**
|
/**
|
||||||
* Initialize all required ExecutableCommand objects.
|
* Initialize all required ExecutableCommand objects.
|
||||||
*
|
*
|
||||||
* @param injector the injector
|
* @param commandFactory factory to create command objects
|
||||||
* @param commandClasses the classes to instantiate
|
* @param commandClasses the classes to instantiate
|
||||||
*/
|
*/
|
||||||
private void initializeCommands(Injector injector,
|
private void initializeCommands(Factory<ExecutableCommand> commandFactory,
|
||||||
Set<Class<? extends ExecutableCommand>> commandClasses) {
|
Set<Class<? extends ExecutableCommand>> commandClasses) {
|
||||||
for (Class<? extends ExecutableCommand> clazz : commandClasses) {
|
for (Class<? extends ExecutableCommand> clazz : commandClasses) {
|
||||||
commands.put(clazz, injector.newInstance(clazz));
|
commands.put(clazz, commandFactory.newInstance(clazz));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import fr.xephi.authme.command.executable.authme.SpawnCommand;
|
|||||||
import fr.xephi.authme.command.executable.authme.SwitchAntiBotCommand;
|
import fr.xephi.authme.command.executable.authme.SwitchAntiBotCommand;
|
||||||
import fr.xephi.authme.command.executable.authme.UnregisterAdminCommand;
|
import fr.xephi.authme.command.executable.authme.UnregisterAdminCommand;
|
||||||
import fr.xephi.authme.command.executable.authme.VersionCommand;
|
import fr.xephi.authme.command.executable.authme.VersionCommand;
|
||||||
|
import fr.xephi.authme.command.executable.authme.debug.DebugCommand;
|
||||||
import fr.xephi.authme.command.executable.captcha.CaptchaCommand;
|
import fr.xephi.authme.command.executable.captcha.CaptchaCommand;
|
||||||
import fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand;
|
import fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand;
|
||||||
import fr.xephi.authme.command.executable.email.AddEmailCommand;
|
import fr.xephi.authme.command.executable.email.AddEmailCommand;
|
||||||
@ -37,6 +38,7 @@ import fr.xephi.authme.command.executable.register.RegisterCommand;
|
|||||||
import fr.xephi.authme.command.executable.unregister.UnregisterCommand;
|
import fr.xephi.authme.command.executable.unregister.UnregisterCommand;
|
||||||
import fr.xephi.authme.permission.AdminPermission;
|
import fr.xephi.authme.permission.AdminPermission;
|
||||||
import fr.xephi.authme.permission.PlayerPermission;
|
import fr.xephi.authme.permission.PlayerPermission;
|
||||||
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -298,6 +300,19 @@ public class CommandInitializer {
|
|||||||
.executableCommand(MessagesCommand.class)
|
.executableCommand(MessagesCommand.class)
|
||||||
.register();
|
.register();
|
||||||
|
|
||||||
|
CommandDescription.builder()
|
||||||
|
.parent(AUTHME_BASE)
|
||||||
|
.labels("debug", "dbg")
|
||||||
|
.description("Debug features")
|
||||||
|
.detailedDescription("Allows various operations for debugging.")
|
||||||
|
.withArgument("child", "The child to execute", true)
|
||||||
|
.withArgument(".", "meaning varies", true)
|
||||||
|
.withArgument(".", "meaning varies", true)
|
||||||
|
.withArgument(".", "meaning varies", true)
|
||||||
|
.permission(PlayerStatePermission.DEBUG_COMMAND)
|
||||||
|
.executableCommand(DebugCommand.class)
|
||||||
|
.register();
|
||||||
|
|
||||||
// Register the base login command
|
// Register the base login command
|
||||||
final CommandDescription LOGIN_BASE = CommandDescription.builder()
|
final CommandDescription LOGIN_BASE = CommandDescription.builder()
|
||||||
.parent(null)
|
.parent(null)
|
||||||
|
@ -2,8 +2,8 @@ package fr.xephi.authme.command;
|
|||||||
|
|
||||||
import fr.xephi.authme.command.executable.HelpCommand;
|
import fr.xephi.authme.command.executable.HelpCommand;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -45,7 +45,7 @@ public class CommandMapper {
|
|||||||
* @return The generated {@link FoundCommandResult}
|
* @return The generated {@link FoundCommandResult}
|
||||||
*/
|
*/
|
||||||
public FoundCommandResult mapPartsToCommand(CommandSender sender, final List<String> parts) {
|
public FoundCommandResult mapPartsToCommand(CommandSender sender, final List<String> parts) {
|
||||||
if (CollectionUtils.isEmpty(parts)) {
|
if (Utils.isCollectionEmpty(parts)) {
|
||||||
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +123,9 @@ public class CommandMapper {
|
|||||||
|
|
||||||
private CommandDescription getBaseCommand(String label) {
|
private CommandDescription getBaseCommand(String label) {
|
||||||
String baseLabel = label.toLowerCase();
|
String baseLabel = label.toLowerCase();
|
||||||
|
if (baseLabel.startsWith("authme:")) {
|
||||||
|
baseLabel = baseLabel.substring("authme:".length());
|
||||||
|
}
|
||||||
for (CommandDescription command : baseCommands) {
|
for (CommandDescription command : baseCommands) {
|
||||||
if (command.hasLabel(baseLabel)) {
|
if (command.hasLabel(baseLabel)) {
|
||||||
return command;
|
return command;
|
||||||
@ -142,7 +145,7 @@ public class CommandMapper {
|
|||||||
* @return A command if there was a complete match (including proper argument count), null otherwise
|
* @return A command if there was a complete match (including proper argument count), null otherwise
|
||||||
*/
|
*/
|
||||||
private static CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
|
private static CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
|
||||||
if (CollectionUtils.isEmpty(parts)) {
|
if (Utils.isCollectionEmpty(parts)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import ch.jalu.injector.Injector;
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
@ -13,6 +12,7 @@ import fr.xephi.authme.datasource.converter.RoyalAuthConverter;
|
|||||||
import fr.xephi.authme.datasource.converter.SqliteToSql;
|
import fr.xephi.authme.datasource.converter.SqliteToSql;
|
||||||
import fr.xephi.authme.datasource.converter.vAuthConverter;
|
import fr.xephi.authme.datasource.converter.vAuthConverter;
|
||||||
import fr.xephi.authme.datasource.converter.xAuthConverter;
|
import fr.xephi.authme.datasource.converter.xAuthConverter;
|
||||||
|
import fr.xephi.authme.initialization.factory.Factory;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
@ -37,7 +37,7 @@ public class ConverterCommand implements ExecutableCommand {
|
|||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Injector injector;
|
private Factory<Converter> converterFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||||
@ -52,7 +52,7 @@ public class ConverterCommand implements ExecutableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the proper converter instance
|
// Get the proper converter instance
|
||||||
final Converter converter = injector.newInstance(converterClass);
|
final Converter converter = converterFactory.newInstance(converterClass);
|
||||||
|
|
||||||
// Run the convert job
|
// Run the convert job
|
||||||
bukkitService.runTaskAsynchronously(new Runnable() {
|
bukkitService.runTaskAsynchronously(new Runnable() {
|
||||||
|
@ -11,10 +11,10 @@ import fr.xephi.authme.message.MessageKey;
|
|||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,8 +44,7 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
ConsoleLogger.setLoggingOptions(settings);
|
ConsoleLogger.setLoggingOptions(settings);
|
||||||
// We do not change database type for consistency issues, but we'll output a note in the logs
|
// We do not change database type for consistency issues, but we'll output a note in the logs
|
||||||
if (!settings.getProperty(DatabaseSettings.BACKEND).equals(dataSource.getType())) {
|
if (!settings.getProperty(DatabaseSettings.BACKEND).equals(dataSource.getType())) {
|
||||||
ConsoleLogger.info("Note: cannot change database type during /authme reload");
|
Utils.logAndSendMessage(sender, "Note: cannot change database type during /authme reload");
|
||||||
sender.sendMessage("Note: cannot change database type during /authme reload");
|
|
||||||
}
|
}
|
||||||
performReloadOnServices();
|
performReloadOnServices();
|
||||||
commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
||||||
@ -57,14 +56,10 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void performReloadOnServices() {
|
private void performReloadOnServices() {
|
||||||
Collection<Reloadable> reloadables = injector.retrieveAllOfType(Reloadable.class);
|
injector.retrieveAllOfType(Reloadable.class)
|
||||||
for (Reloadable reloadable : reloadables) {
|
.forEach(r -> r.reload());
|
||||||
reloadable.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<SettingsDependent> settingsDependents = injector.retrieveAllOfType(SettingsDependent.class);
|
injector.retrieveAllOfType(SettingsDependent.class)
|
||||||
for (SettingsDependent dependent : settingsDependents) {
|
.forEach(s -> s.reload(settings));
|
||||||
dependent.reload(settings);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.service.GeoIpService;
|
||||||
|
import fr.xephi.authme.service.ValidationService;
|
||||||
|
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the GeoIP information as returned by the geoIpService.
|
||||||
|
*/
|
||||||
|
class CountryLookup implements DebugSection {
|
||||||
|
|
||||||
|
private static final Pattern IS_IP_ADDR = Pattern.compile("(\\d{1,3}\\.){3}\\d{1,3}");
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GeoIpService geoIpService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "cty";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Check country protection / country data";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
sender.sendMessage("Check player: /authme debug cty Bobby");
|
||||||
|
sender.sendMessage("Check IP address: /authme debug cty 127.123.45.67");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String argument = arguments.get(0);
|
||||||
|
if (IS_IP_ADDR.matcher(argument).matches()) {
|
||||||
|
outputInfoForIpAddr(sender, argument);
|
||||||
|
} else {
|
||||||
|
outputInfoForPlayer(sender, argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void outputInfoForIpAddr(CommandSender sender, String ipAddr) {
|
||||||
|
sender.sendMessage("IP '" + ipAddr + "' maps to country '" + geoIpService.getCountryCode(ipAddr)
|
||||||
|
+ "' (" + geoIpService.getCountryName(ipAddr) + ")");
|
||||||
|
if (validationService.isCountryAdmitted(ipAddr)) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_GREEN + "This IP address' country is not blocked");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "This IP address' country is blocked from the server");
|
||||||
|
}
|
||||||
|
sender.sendMessage("Note: if " + ProtectionSettings.ENABLE_PROTECTION + " is false no country is blocked");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void outputInfoForPlayer(CommandSender sender, String name) {
|
||||||
|
PlayerAuth auth = dataSource.getAuth(name);
|
||||||
|
if (auth == null) {
|
||||||
|
sender.sendMessage("No player with name '" + name + "'");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Player '" + name + "' has IP address " + auth.getIp());
|
||||||
|
outputInfoForIpAddr(sender, auth.getIp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
|
import fr.xephi.authme.initialization.factory.Factory;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug command main.
|
||||||
|
*/
|
||||||
|
public class DebugCommand implements ExecutableCommand {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Factory<DebugSection> debugSectionFactory;
|
||||||
|
|
||||||
|
private Set<Class<? extends DebugSection>> sectionClasses =
|
||||||
|
ImmutableSet.of(PermissionGroups.class, TestEmailSender.class, CountryLookup.class);
|
||||||
|
|
||||||
|
private Map<String, DebugSection> sections;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||||
|
DebugSection debugSection = getDebugSection(arguments);
|
||||||
|
if (debugSection == null) {
|
||||||
|
sender.sendMessage("Available sections:");
|
||||||
|
getSections().values()
|
||||||
|
.forEach(e -> sender.sendMessage("- " + e.getName() + ": " + e.getDescription()));
|
||||||
|
} else {
|
||||||
|
debugSection.execute(sender, arguments.subList(1, arguments.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DebugSection getDebugSection(List<String> arguments) {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getSections().get(arguments.get(0).toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lazy getter
|
||||||
|
private Map<String, DebugSection> getSections() {
|
||||||
|
if (sections == null) {
|
||||||
|
Map<String, DebugSection> sections = new HashMap<>();
|
||||||
|
for (Class<? extends DebugSection> sectionClass : sectionClasses) {
|
||||||
|
DebugSection section = debugSectionFactory.newInstance(sectionClass);
|
||||||
|
sections.put(section.getName(), section);
|
||||||
|
}
|
||||||
|
this.sections = sections;
|
||||||
|
}
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A debug section: "child" command of the debug command.
|
||||||
|
*/
|
||||||
|
interface DebugSection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name to get to this child command
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return short description of the child command
|
||||||
|
*/
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the debug child command.
|
||||||
|
*
|
||||||
|
* @param sender the sender executing the command
|
||||||
|
* @param arguments the arguments, without the label of the child command
|
||||||
|
*/
|
||||||
|
void execute(CommandSender sender, List<String> arguments);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the permission groups of a player.
|
||||||
|
*/
|
||||||
|
class PermissionGroups implements DebugSection {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "groups";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Show permission groups a player belongs to";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
String name = arguments.isEmpty() ? sender.getName() : arguments.get(0);
|
||||||
|
Player player = Bukkit.getPlayer(name);
|
||||||
|
if (player == null) {
|
||||||
|
sender.sendMessage("Player " + name + " could not be found");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Player " + name + " has permission groups: "
|
||||||
|
+ String.join(", ", permissionsManager.getGroups(player)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.mail.SendMailSSL;
|
||||||
|
import org.apache.commons.mail.EmailException;
|
||||||
|
import org.apache.commons.mail.HtmlEmail;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends out a test email.
|
||||||
|
*/
|
||||||
|
class TestEmailSender implements DebugSection {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SendMailSSL sendMailSSL;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Server server;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "mail";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Sends out a test email";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
if (!sendMailSSL.hasAllInformation()) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml " +
|
||||||
|
"for sending emails. Please check your config.yml");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String email = getEmail(sender, arguments);
|
||||||
|
|
||||||
|
// getEmail() takes care of informing the sender of the error if email == null
|
||||||
|
if (email != null) {
|
||||||
|
boolean sendMail = sendTestEmail(email);
|
||||||
|
if (sendMail) {
|
||||||
|
sender.sendMessage("Test email sent to " + email + " with success");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Failed to send test mail to " + email + "; please check your logs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getEmail(CommandSender sender, List<String> arguments) {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
PlayerAuth auth = dataSource.getAuth(sender.getName());
|
||||||
|
if (auth == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Please provide an email address, "
|
||||||
|
+ "e.g. /authme debug mail test@example.com");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String email = auth.getEmail();
|
||||||
|
if (email == null || "your@email.com".equals(email)) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "No email set for your account! Please use /authme debug mail <email>");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return email;
|
||||||
|
} else {
|
||||||
|
String email = arguments.get(0);
|
||||||
|
if (email.contains("@")) {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
sender.sendMessage(ChatColor.RED + "Invalid email! Usage: /authme debug mail test@example.com");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sendTestEmail(String email) {
|
||||||
|
HtmlEmail htmlEmail;
|
||||||
|
try {
|
||||||
|
htmlEmail = sendMailSSL.initializeMail(email);
|
||||||
|
} catch (EmailException e) {
|
||||||
|
ConsoleLogger.logException("Failed to create email for sample email:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlEmail.setSubject("AuthMe test email");
|
||||||
|
String message = "Hello there!<br />This is a sample email sent to you from a Minecraft server ("
|
||||||
|
+ server.getName() + ") via /authme debug mail. If you're seeing this, sending emails should be fine.";
|
||||||
|
return sendMailSSL.sendEmail(message, htmlEmail);
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package fr.xephi.authme.command.executable.captcha;
|
|||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.data.CaptchaManager;
|
import fr.xephi.authme.data.CaptchaManager;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
@ -5,24 +5,31 @@ import fr.xephi.authme.command.PlayerCommand;
|
|||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.mail.SendMailSSL;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.mail.EmailService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.message.Messages;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.service.RecoveryCodeService;
|
import fr.xephi.authme.service.RecoveryCodeService;
|
||||||
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.util.RandomStringUtils;
|
import fr.xephi.authme.util.RandomStringUtils;
|
||||||
|
import fr.xephi.authme.util.expiring.Duration;
|
||||||
|
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
|
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command for password recovery by email.
|
* Command for password recovery by email.
|
||||||
*/
|
*/
|
||||||
public class RecoverEmailCommand extends PlayerCommand {
|
public class RecoverEmailCommand extends PlayerCommand implements Reloadable {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PasswordSecurity passwordSecurity;
|
private PasswordSecurity passwordSecurity;
|
||||||
@ -37,17 +44,28 @@ public class RecoverEmailCommand extends PlayerCommand {
|
|||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SendMailSSL sendMailSsl;
|
private EmailService emailService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private RecoveryCodeService recoveryCodeService;
|
private RecoveryCodeService recoveryCodeService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Messages messages;
|
||||||
|
|
||||||
|
private ExpiringSet<String> emailCooldown;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void initEmailCooldownSet() {
|
||||||
|
emailCooldown = new ExpiringSet<>(
|
||||||
|
commonService.getProperty(SecuritySettings.EMAIL_RECOVERY_COOLDOWN_SECONDS), TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
protected void runCommand(Player player, List<String> arguments) {
|
||||||
final String playerMail = arguments.get(0);
|
final String playerMail = arguments.get(0);
|
||||||
final String playerName = player.getName();
|
final String playerName = player.getName();
|
||||||
|
|
||||||
if (!sendMailSsl.hasAllInformation()) {
|
if (!emailService.hasAllInformation()) {
|
||||||
ConsoleLogger.warning("Mail API is not set");
|
ConsoleLogger.warning("Mail API is not set");
|
||||||
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||||
return;
|
return;
|
||||||
@ -78,15 +96,29 @@ public class RecoverEmailCommand extends PlayerCommand {
|
|||||||
processRecoveryCode(player, arguments.get(1), email);
|
processRecoveryCode(player, arguments.get(1), email);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
boolean maySendMail = checkEmailCooldown(player);
|
||||||
|
if (maySendMail) {
|
||||||
generateAndSendNewPassword(player, email);
|
generateAndSendNewPassword(player, email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
emailCooldown.setExpiration(
|
||||||
|
commonService.getProperty(SecuritySettings.EMAIL_RECOVERY_COOLDOWN_SECONDS), TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
private void createAndSendRecoveryCode(Player player, String email) {
|
private void createAndSendRecoveryCode(Player player, String email) {
|
||||||
|
if (!checkEmailCooldown(player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String recoveryCode = recoveryCodeService.generateCode(player.getName());
|
String recoveryCode = recoveryCodeService.generateCode(player.getName());
|
||||||
boolean couldSendMail = sendMailSsl.sendRecoveryCode(player.getName(), email, recoveryCode);
|
boolean couldSendMail = emailService.sendRecoveryCode(player.getName(), email, recoveryCode);
|
||||||
if (couldSendMail) {
|
if (couldSendMail) {
|
||||||
commonService.send(player, MessageKey.RECOVERY_CODE_SENT);
|
commonService.send(player, MessageKey.RECOVERY_CODE_SENT);
|
||||||
|
emailCooldown.add(player.getName().toLowerCase());
|
||||||
} else {
|
} else {
|
||||||
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
||||||
}
|
}
|
||||||
@ -108,11 +140,22 @@ public class RecoverEmailCommand extends PlayerCommand {
|
|||||||
HashedPassword hashNew = passwordSecurity.computeHash(thePass, name);
|
HashedPassword hashNew = passwordSecurity.computeHash(thePass, name);
|
||||||
|
|
||||||
dataSource.updatePassword(name, hashNew);
|
dataSource.updatePassword(name, hashNew);
|
||||||
boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, thePass);
|
boolean couldSendMail = emailService.sendPasswordMail(name, email, thePass);
|
||||||
if (couldSendMail) {
|
if (couldSendMail) {
|
||||||
commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
commonService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||||
|
emailCooldown.add(player.getName().toLowerCase());
|
||||||
} else {
|
} else {
|
||||||
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkEmailCooldown(Player player) {
|
||||||
|
Duration waitDuration = emailCooldown.getExpiration(player.getName().toLowerCase());
|
||||||
|
if (waitDuration.getDuration() > 0) {
|
||||||
|
String durationText = messages.formatDuration(waitDuration);
|
||||||
|
messages.send(player, MessageKey.EMAIL_COOLDOWN_ERROR, durationText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package fr.xephi.authme.command.executable.register;
|
|||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.mail.SendMailSSL;
|
import fr.xephi.authme.mail.EmailService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.process.register.RegisterSecondaryArgument;
|
import fr.xephi.authme.process.register.RegisterSecondaryArgument;
|
||||||
@ -37,7 +37,7 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
private CommonService commonService;
|
private CommonService commonService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SendMailSSL sendMailSsl;
|
private EmailService emailService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
@ -127,7 +127,7 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleEmailRegistration(Player player, List<String> arguments) {
|
private void handleEmailRegistration(Player player, List<String> arguments) {
|
||||||
if (!sendMailSsl.hasAllInformation()) {
|
if (!emailService.hasAllInformation()) {
|
||||||
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
commonService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||||
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
|
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
|
||||||
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
package fr.xephi.authme.data;
|
package fr.xephi.authme.data;
|
||||||
|
|
||||||
|
import fr.xephi.authme.initialization.HasCleanup;
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.util.RandomStringUtils;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
|
import fr.xephi.authme.util.RandomStringUtils;
|
||||||
|
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager for the handling of captchas.
|
* Manager for the handling of captchas.
|
||||||
*/
|
*/
|
||||||
public class CaptchaManager implements SettingsDependent {
|
public class CaptchaManager implements SettingsDependent, HasCleanup {
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Integer> playerCounts;
|
private final TimedCounter<String> playerCounts;
|
||||||
private final ConcurrentHashMap<String, String> captchaCodes;
|
private final ConcurrentHashMap<String, String> captchaCodes;
|
||||||
|
|
||||||
private boolean isEnabled;
|
private boolean isEnabled;
|
||||||
@ -22,8 +25,9 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CaptchaManager(Settings settings) {
|
CaptchaManager(Settings settings) {
|
||||||
this.playerCounts = new ConcurrentHashMap<>();
|
|
||||||
this.captchaCodes = new ConcurrentHashMap<>();
|
this.captchaCodes = new ConcurrentHashMap<>();
|
||||||
|
long countTimeout = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET);
|
||||||
|
this.playerCounts = new TimedCounter<>(countTimeout, TimeUnit.MINUTES);
|
||||||
reload(settings);
|
reload(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,12 +39,7 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
public void increaseCount(String name) {
|
public void increaseCount(String name) {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
String playerLower = name.toLowerCase();
|
String playerLower = name.toLowerCase();
|
||||||
Integer currentCount = playerCounts.get(playerLower);
|
playerCounts.increment(playerLower);
|
||||||
if (currentCount == null) {
|
|
||||||
playerCounts.put(playerLower, 1);
|
|
||||||
} else {
|
|
||||||
playerCounts.put(playerLower, currentCount + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,21 +50,7 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
* @return true if the player has to solve a captcha, false otherwise
|
* @return true if the player has to solve a captcha, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isCaptchaRequired(String name) {
|
public boolean isCaptchaRequired(String name) {
|
||||||
if (isEnabled) {
|
return isEnabled && playerCounts.get(name.toLowerCase()) >= threshold;
|
||||||
Integer count = playerCounts.get(name.toLowerCase());
|
|
||||||
return count != null && count >= threshold;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the stored captcha code for the player.
|
|
||||||
*
|
|
||||||
* @param name the player's name
|
|
||||||
* @return the code the player is required to enter, or null if none registered
|
|
||||||
*/
|
|
||||||
public String getCaptchaCode(String name) {
|
|
||||||
return captchaCodes.get(name.toLowerCase());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +60,7 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
* @return the code the player is required to enter
|
* @return the code the player is required to enter
|
||||||
*/
|
*/
|
||||||
public String getCaptchaCodeOrGenerateNew(String name) {
|
public String getCaptchaCodeOrGenerateNew(String name) {
|
||||||
String code = getCaptchaCode(name);
|
String code = captchaCodes.get(name.toLowerCase());
|
||||||
return code == null ? generateCode(name) : code;
|
return code == null ? generateCode(name) : code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +112,13 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
||||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
||||||
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
||||||
|
long countTimeout = settings.getProperty(SecuritySettings.CAPTCHA_COUNT_MINUTES_BEFORE_RESET);
|
||||||
|
playerCounts.setExpiration(countTimeout, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performCleanup() {
|
||||||
|
playerCounts.removeExpiredEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@ import fr.xephi.authme.initialization.HasCleanup;
|
|||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
|
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Iterator;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages sessions, allowing players to be automatically logged in if they join again
|
* Manages sessions, allowing players to be automatically logged in if they join again
|
||||||
@ -19,15 +16,14 @@ import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE;
|
|||||||
*/
|
*/
|
||||||
public class SessionManager implements SettingsDependent, HasCleanup {
|
public class SessionManager implements SettingsDependent, HasCleanup {
|
||||||
|
|
||||||
// Player -> expiration of session in milliseconds
|
private final ExpiringSet<String> sessions;
|
||||||
private final Map<String, Long> sessions = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
private int timeoutInMinutes;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SessionManager(Settings settings) {
|
SessionManager(Settings settings) {
|
||||||
reload(settings);
|
long timeout = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT);
|
||||||
|
sessions = new ExpiringSet<>(timeout, TimeUnit.MINUTES);
|
||||||
|
enabled = timeout > 0 && settings.getProperty(PluginSettings.SESSIONS_ENABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,13 +33,7 @@ public class SessionManager implements SettingsDependent, HasCleanup {
|
|||||||
* @return True if a session is found.
|
* @return True if a session is found.
|
||||||
*/
|
*/
|
||||||
public boolean hasSession(String name) {
|
public boolean hasSession(String name) {
|
||||||
if (enabled) {
|
return enabled && sessions.contains(name.toLowerCase());
|
||||||
Long timeout = sessions.get(name.toLowerCase());
|
|
||||||
if (timeout != null) {
|
|
||||||
return System.currentTimeMillis() <= timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,8 +43,7 @@ public class SessionManager implements SettingsDependent, HasCleanup {
|
|||||||
*/
|
*/
|
||||||
public void addSession(String name) {
|
public void addSession(String name) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
long timeout = System.currentTimeMillis() + timeoutInMinutes * MILLIS_PER_MINUTE;
|
sessions.add(name.toLowerCase());
|
||||||
sessions.put(name.toLowerCase(), timeout);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +53,13 @@ public class SessionManager implements SettingsDependent, HasCleanup {
|
|||||||
* @param name The name of the player.
|
* @param name The name of the player.
|
||||||
*/
|
*/
|
||||||
public void removeSession(String name) {
|
public void removeSession(String name) {
|
||||||
this.sessions.remove(name.toLowerCase());
|
sessions.remove(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reload(Settings settings) {
|
public void reload(Settings settings) {
|
||||||
timeoutInMinutes = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT);
|
long timeoutInMinutes = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT);
|
||||||
|
sessions.setExpiration(timeoutInMinutes, TimeUnit.MINUTES);
|
||||||
boolean oldEnabled = enabled;
|
boolean oldEnabled = enabled;
|
||||||
enabled = timeoutInMinutes > 0 && settings.getProperty(PluginSettings.SESSIONS_ENABLED);
|
enabled = timeoutInMinutes > 0 && settings.getProperty(PluginSettings.SESSIONS_ENABLED);
|
||||||
|
|
||||||
@ -82,16 +72,8 @@ public class SessionManager implements SettingsDependent, HasCleanup {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performCleanup() {
|
public void performCleanup() {
|
||||||
if (!enabled) {
|
if (enabled) {
|
||||||
return;
|
sessions.removeExpiredEntries();
|
||||||
}
|
|
||||||
final long currentTime = System.currentTimeMillis();
|
|
||||||
Iterator<Map.Entry<String, Long>> iterator = sessions.entrySet().iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Map.Entry<String, Long> entry = iterator.next();
|
|
||||||
if (entry.getValue() < currentTime) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package fr.xephi.authme.data;
|
package fr.xephi.authme.data;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import fr.xephi.authme.initialization.HasCleanup;
|
import fr.xephi.authme.initialization.HasCleanup;
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.SecuritySettings.TEMPBAN_MINUTES_BEFORE_RESET;
|
import static fr.xephi.authme.settings.properties.SecuritySettings.TEMPBAN_MINUTES_BEFORE_RESET;
|
||||||
import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE;
|
import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE;
|
||||||
@ -25,7 +25,7 @@ import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE;
|
|||||||
*/
|
*/
|
||||||
public class TempbanManager implements SettingsDependent, HasCleanup {
|
public class TempbanManager implements SettingsDependent, HasCleanup {
|
||||||
|
|
||||||
private final Map<String, Map<String, TimedCounter>> ipLoginFailureCounts;
|
private final Map<String, TimedCounter<String>> ipLoginFailureCounts;
|
||||||
private final BukkitService bukkitService;
|
private final BukkitService bukkitService;
|
||||||
private final Messages messages;
|
private final Messages messages;
|
||||||
|
|
||||||
@ -50,18 +50,9 @@ public class TempbanManager implements SettingsDependent, HasCleanup {
|
|||||||
*/
|
*/
|
||||||
public void increaseCount(String address, String name) {
|
public void increaseCount(String address, String name) {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
Map<String, TimedCounter> countsByName = ipLoginFailureCounts.get(address);
|
TimedCounter<String> countsByName = ipLoginFailureCounts.computeIfAbsent(
|
||||||
if (countsByName == null) {
|
address, k -> new TimedCounter<>(resetThreshold, TimeUnit.MINUTES));
|
||||||
countsByName = new ConcurrentHashMap<>();
|
countsByName.increment(name);
|
||||||
ipLoginFailureCounts.put(address, countsByName);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimedCounter counter = countsByName.get(name);
|
|
||||||
if (counter == null) {
|
|
||||||
countsByName.put(name, new TimedCounter(1));
|
|
||||||
} else {
|
|
||||||
counter.increment(resetThreshold);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +64,9 @@ public class TempbanManager implements SettingsDependent, HasCleanup {
|
|||||||
*/
|
*/
|
||||||
public void resetCount(String address, String name) {
|
public void resetCount(String address, String name) {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
Map<String, TimedCounter> map = ipLoginFailureCounts.get(address);
|
TimedCounter<String> counter = ipLoginFailureCounts.get(address);
|
||||||
if (map != null) {
|
if (counter != null) {
|
||||||
map.remove(name);
|
counter.remove(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,13 +79,9 @@ public class TempbanManager implements SettingsDependent, HasCleanup {
|
|||||||
*/
|
*/
|
||||||
public boolean shouldTempban(String address) {
|
public boolean shouldTempban(String address) {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
Map<String, TimedCounter> countsByName = ipLoginFailureCounts.get(address);
|
TimedCounter<String> countsByName = ipLoginFailureCounts.get(address);
|
||||||
if (countsByName != null) {
|
if (countsByName != null) {
|
||||||
int total = 0;
|
return countsByName.total() >= threshold;
|
||||||
for (TimedCounter counter : countsByName.values()) {
|
|
||||||
total += counter.getCount(resetThreshold);
|
|
||||||
}
|
|
||||||
return total >= threshold;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -137,56 +124,9 @@ public class TempbanManager implements SettingsDependent, HasCleanup {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performCleanup() {
|
public void performCleanup() {
|
||||||
for (Map<String, TimedCounter> countsByIp : ipLoginFailureCounts.values()) {
|
for (TimedCounter<String> countsByIp : ipLoginFailureCounts.values()) {
|
||||||
Iterator<TimedCounter> it = countsByIp.values().iterator();
|
countsByIp.removeExpiredEntries();
|
||||||
while (it.hasNext()) {
|
}
|
||||||
TimedCounter counter = it.next();
|
ipLoginFailureCounts.entrySet().removeIf(e -> e.getValue().isEmpty());
|
||||||
if (counter.getCount(resetThreshold) == 0) {
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Counter with an associated timestamp, keeping track of when the last entry has been added.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static final class TimedCounter {
|
|
||||||
|
|
||||||
private int counter;
|
|
||||||
private long lastIncrementTimestamp = System.currentTimeMillis();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param start the initial value to set the counter to
|
|
||||||
*/
|
|
||||||
TimedCounter(int start) {
|
|
||||||
this.counter = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the count, taking into account the last entry timestamp.
|
|
||||||
*
|
|
||||||
* @param threshold the threshold in milliseconds until when to consider a counter
|
|
||||||
* @return the counter's value, or {@code 0} if it was last incremented longer ago than the threshold
|
|
||||||
*/
|
|
||||||
int getCount(long threshold) {
|
|
||||||
if (System.currentTimeMillis() - lastIncrementTimestamp > threshold) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the counter, taking into account the last entry timestamp.
|
|
||||||
*
|
|
||||||
* @param threshold in milliseconds, the time span until which to consider the existing number
|
|
||||||
*/
|
|
||||||
void increment(long threshold) {
|
|
||||||
counter = getCount(threshold) + 1;
|
|
||||||
lastIncrementTimestamp = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package fr.xephi.authme.data.limbo;
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
import fr.xephi.authme.data.backup.LimboPlayerStorage;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.settings.Settings;
|
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@ -23,14 +20,11 @@ public class LimboCache {
|
|||||||
private final Map<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
private final Map<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private LimboPlayerStorage limboPlayerStorage;
|
private LimboPlayerStorage limboPlayerStorage;
|
||||||
private Settings settings;
|
|
||||||
private PermissionsManager permissionsManager;
|
private PermissionsManager permissionsManager;
|
||||||
private SpawnLoader spawnLoader;
|
private SpawnLoader spawnLoader;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LimboCache(Settings settings, PermissionsManager permissionsManager,
|
LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader, LimboPlayerStorage limboPlayerStorage) {
|
||||||
SpawnLoader spawnLoader, LimboPlayerStorage limboPlayerStorage) {
|
|
||||||
this.settings = settings;
|
|
||||||
this.permissionsManager = permissionsManager;
|
this.permissionsManager = permissionsManager;
|
||||||
this.spawnLoader = spawnLoader;
|
this.spawnLoader = spawnLoader;
|
||||||
this.limboPlayerStorage = limboPlayerStorage;
|
this.limboPlayerStorage = limboPlayerStorage;
|
||||||
@ -52,6 +46,7 @@ public class LimboCache {
|
|||||||
if (permissionsManager.hasGroupSupport()) {
|
if (permissionsManager.hasGroupSupport()) {
|
||||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
playerGroup = permissionsManager.getPrimaryGroup(player);
|
||||||
}
|
}
|
||||||
|
ConsoleLogger.debug("Player `{0}` has primary group `{1}`", player.getName(), playerGroup);
|
||||||
|
|
||||||
if (limboPlayerStorage.hasData(player)) {
|
if (limboPlayerStorage.hasData(player)) {
|
||||||
LimboPlayer cache = limboPlayerStorage.readData(player);
|
LimboPlayer cache = limboPlayerStorage.readData(player);
|
||||||
@ -85,14 +80,13 @@ public class LimboCache {
|
|||||||
float flySpeed = data.getFlySpeed();
|
float flySpeed = data.getFlySpeed();
|
||||||
// Reset the speed value if it was 0
|
// Reset the speed value if it was 0
|
||||||
if (walkSpeed < 0.01f) {
|
if (walkSpeed < 0.01f) {
|
||||||
walkSpeed = 0.2f;
|
walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
||||||
}
|
}
|
||||||
if (flySpeed < 0.01f) {
|
if (flySpeed < 0.01f) {
|
||||||
flySpeed = 0.2f;
|
flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
||||||
}
|
}
|
||||||
player.setWalkSpeed(walkSpeed);
|
player.setWalkSpeed(walkSpeed);
|
||||||
player.setFlySpeed(flySpeed);
|
player.setFlySpeed(flySpeed);
|
||||||
restoreGroup(player, data.getGroup());
|
|
||||||
data.clearTasks();
|
data.clearTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,11 +148,4 @@ public class LimboCache {
|
|||||||
removeFromCache(player);
|
removeFromCache(player);
|
||||||
addPlayerData(player);
|
addPlayerData(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreGroup(Player player, String group) {
|
|
||||||
if (!StringUtils.isEmpty(group) && permissionsManager.hasGroupSupport()
|
|
||||||
&& settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
|
||||||
permissionsManager.setGroup(player, group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@ import org.bukkit.scheduler.BukkitTask;
|
|||||||
*/
|
*/
|
||||||
public class LimboPlayer {
|
public class LimboPlayer {
|
||||||
|
|
||||||
|
public static final float DEFAULT_WALK_SPEED = 0.2f;
|
||||||
|
public static final float DEFAULT_FLY_SPEED = 0.1f;
|
||||||
|
|
||||||
private final boolean canFly;
|
private final boolean canFly;
|
||||||
private final boolean operator;
|
private final boolean operator;
|
||||||
private final String group;
|
private final String group;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fr.xephi.authme.data.backup;
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@ -10,11 +10,10 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonSerializationContext;
|
import com.google.gson.JsonSerializationContext;
|
||||||
import com.google.gson.JsonSerializer;
|
import com.google.gson.JsonSerializer;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
import fr.xephi.authme.util.FileUtils;
|
import fr.xephi.authme.util.FileUtils;
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -149,8 +148,8 @@ public class LimboPlayerStorage {
|
|||||||
String group = "";
|
String group = "";
|
||||||
boolean operator = false;
|
boolean operator = false;
|
||||||
boolean canFly = false;
|
boolean canFly = false;
|
||||||
float walkSpeed = 0.2f;
|
float walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
||||||
float flySpeed = 0.2f;
|
float flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
||||||
|
|
||||||
JsonElement e;
|
JsonElement e;
|
||||||
if ((e = jsonObject.getAsJsonObject("location")) != null) {
|
if ((e = jsonObject.getAsJsonObject("location")) != null) {
|
@ -6,6 +6,8 @@ import fr.xephi.authme.settings.properties.DatabaseSettings;
|
|||||||
/**
|
/**
|
||||||
* Database column names.
|
* Database column names.
|
||||||
*/
|
*/
|
||||||
|
// Justification: String is immutable and this class is used to easily access the configurable column names
|
||||||
|
@SuppressWarnings({"checkstyle:VisibilityModifier", "checkstyle:MemberName", "checkstyle:AbbreviationAsWordInName"})
|
||||||
public final class Columns {
|
public final class Columns {
|
||||||
|
|
||||||
public final String NAME;
|
public final String NAME;
|
||||||
|
@ -45,7 +45,10 @@ public class MySQL implements DataSource {
|
|||||||
private HikariDataSource ds;
|
private HikariDataSource ds;
|
||||||
|
|
||||||
private String phpBbPrefix;
|
private String phpBbPrefix;
|
||||||
|
private String IPBPrefix;
|
||||||
private int phpBbGroup;
|
private int phpBbGroup;
|
||||||
|
private int IPBGroup;
|
||||||
|
private int XFGroup;
|
||||||
private String wordpressPrefix;
|
private String wordpressPrefix;
|
||||||
|
|
||||||
public MySQL(Settings settings) throws ClassNotFoundException, SQLException {
|
public MySQL(Settings settings) throws ClassNotFoundException, SQLException {
|
||||||
@ -96,10 +99,13 @@ public class MySQL implements DataSource {
|
|||||||
this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
|
this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
|
||||||
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
|
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
|
||||||
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
|
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
|
||||||
|
this.IPBPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX);
|
||||||
|
this.IPBGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID);
|
||||||
|
this.XFGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID);
|
||||||
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
||||||
this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
|
this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
|
||||||
if (poolSize == -1) {
|
if (poolSize == -1) {
|
||||||
poolSize = Utils.getCoreCount();
|
poolSize = Utils.getCoreCount()*3;
|
||||||
}
|
}
|
||||||
this.useSSL = settings.getProperty(DatabaseSettings.MYSQL_USE_SSL);
|
this.useSSL = settings.getProperty(DatabaseSettings.MYSQL_USE_SSL);
|
||||||
}
|
}
|
||||||
@ -334,8 +340,39 @@ public class MySQL implements DataSource {
|
|||||||
pst.close();
|
pst.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hashAlgorithm == HashAlgorithm.IPB4){
|
||||||
if (hashAlgorithm == HashAlgorithm.PHPBB) {
|
sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
|
pst = con.prepareStatement(sql);
|
||||||
|
pst.setString(1, auth.getNickname());
|
||||||
|
rs = pst.executeQuery();
|
||||||
|
if (rs.next()){
|
||||||
|
// Update player group in core_members
|
||||||
|
sql = "UPDATE " + IPBPrefix + tableName + " SET "+ tableName + ".member_group_id=? WHERE " + col.NAME + "=?;";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setInt(1, IPBGroup);
|
||||||
|
pst2.setString(2, auth.getNickname());
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
// Get current time without ms
|
||||||
|
long time = System.currentTimeMillis() / 1000;
|
||||||
|
// update joined date
|
||||||
|
sql = "UPDATE " + IPBPrefix + tableName + " SET "+ tableName + ".joined=? WHERE " + col.NAME + "=?;";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setLong(1, time);
|
||||||
|
pst2.setString(2, auth.getNickname());
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
// Update last_visit
|
||||||
|
sql = "UPDATE " + IPBPrefix + tableName + " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setLong(1, time);
|
||||||
|
pst2.setString(2, auth.getNickname());
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
pst.close();
|
||||||
|
} else if (hashAlgorithm == HashAlgorithm.PHPBB) {
|
||||||
sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
pst = con.prepareStatement(sql);
|
pst = con.prepareStatement(sql);
|
||||||
pst.setString(1, auth.getNickname());
|
pst.setString(1, auth.getNickname());
|
||||||
@ -479,6 +516,7 @@ public class MySQL implements DataSource {
|
|||||||
rs = pst.executeQuery();
|
rs = pst.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
int id = rs.getInt(col.ID);
|
int id = rs.getInt(col.ID);
|
||||||
|
// Insert player password, salt in xf_user_authenticate
|
||||||
sql = "INSERT INTO xf_user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)";
|
sql = "INSERT INTO xf_user_authenticate (user_id, scheme_class, data) VALUES (?,?,?)";
|
||||||
pst2 = con.prepareStatement(sql);
|
pst2 = con.prepareStatement(sql);
|
||||||
pst2.setInt(1, id);
|
pst2.setInt(1, id);
|
||||||
@ -490,6 +528,39 @@ public class MySQL implements DataSource {
|
|||||||
pst2.setBlob(3, blob);
|
pst2.setBlob(3, blob);
|
||||||
pst2.executeUpdate();
|
pst2.executeUpdate();
|
||||||
pst2.close();
|
pst2.close();
|
||||||
|
// Update player group in xf_users
|
||||||
|
sql = "UPDATE " + tableName + " SET "+ tableName + ".user_group_id=? WHERE " + col.NAME + "=?;";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setInt(1, XFGroup);
|
||||||
|
pst2.setString(2, auth.getNickname());
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
// Update player permission combination in xf_users
|
||||||
|
sql = "UPDATE " + tableName + " SET "+ tableName + ".permission_combination_id=? WHERE " + col.NAME + "=?;";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setInt(1, XFGroup);
|
||||||
|
pst2.setString(2, auth.getNickname());
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
// Insert player privacy combination in xf_user_privacy
|
||||||
|
sql = "INSERT INTO xf_user_privacy (user_id, allow_view_profile, allow_post_profile, allow_send_personal_conversation, allow_view_identities, allow_receive_news_feed) VALUES (?,?,?,?,?,?)";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setInt(1, id);
|
||||||
|
pst2.setString(2, "everyone");
|
||||||
|
pst2.setString(3, "members");
|
||||||
|
pst2.setString(4, "members");
|
||||||
|
pst2.setString(5, "everyone");
|
||||||
|
pst2.setString(6, "everyone");
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
|
// Insert player group relation in xf_user_group_relation
|
||||||
|
sql = "INSERT INTO xf_user_group_relation (user_id, user_group_id, is_primary) VALUES (?,?,?)";
|
||||||
|
pst2 = con.prepareStatement(sql);
|
||||||
|
pst2.setInt(1, id);
|
||||||
|
pst2.setInt(2, XFGroup);
|
||||||
|
pst2.setString(3, "1");
|
||||||
|
pst2.executeUpdate();
|
||||||
|
pst2.close();
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
pst.close();
|
pst.close();
|
||||||
|
@ -37,7 +37,7 @@ public abstract class AbstractDataSourceConverter<S extends DataSource> implemen
|
|||||||
// which is never the case when a converter is launched from the /authme converter command.
|
// which is never the case when a converter is launched from the /authme converter command.
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender) {
|
public void execute(CommandSender sender) {
|
||||||
if (!destinationType.equals(destination.getType())) {
|
if (destinationType != destination.getType()) {
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
sender.sendMessage("Please configure your connection to "
|
sender.sendMessage("Please configure your connection to "
|
||||||
+ destinationType + " and re-run this command");
|
+ destinationType + " and re-run this command");
|
||||||
@ -59,6 +59,7 @@ public abstract class AbstractDataSourceConverter<S extends DataSource> implemen
|
|||||||
if (destination.isAuthAvailable(auth.getNickname())) {
|
if (destination.isAuthAvailable(auth.getNickname())) {
|
||||||
skippedPlayers.add(auth.getNickname());
|
skippedPlayers.add(auth.getNickname());
|
||||||
} else {
|
} else {
|
||||||
|
adaptPlayerAuth(auth);
|
||||||
destination.saveAuth(auth);
|
destination.saveAuth(auth);
|
||||||
destination.updateQuitLoc(auth);
|
destination.updateQuitLoc(auth);
|
||||||
}
|
}
|
||||||
@ -72,6 +73,15 @@ public abstract class AbstractDataSourceConverter<S extends DataSource> implemen
|
|||||||
+ " to " + destinationType);
|
+ " to " + destinationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts the PlayerAuth from the source before it is saved in the destination.
|
||||||
|
*
|
||||||
|
* @param auth the auth from the source
|
||||||
|
*/
|
||||||
|
protected void adaptPlayerAuth(PlayerAuth auth) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the data source to convert from
|
* @return the data source to convert from
|
||||||
* @throws Exception during initialization of source
|
* @throws Exception during initialization of source
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package fr.xephi.authme.datasource.converter;
|
package fr.xephi.authme.datasource.converter;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.datasource.FlatFile;
|
import fr.xephi.authme.datasource.FlatFile;
|
||||||
|
|
||||||
@ -25,4 +26,11 @@ public class ForceFlatToSqlite extends AbstractDataSourceConverter<FlatFile> {
|
|||||||
public FlatFile getSource() {
|
public FlatFile getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void adaptPlayerAuth(PlayerAuth auth) {
|
||||||
|
// Issue #1120: FlatFile returns PlayerAuth objects with realname = lower-case name all the time.
|
||||||
|
// We don't want to take this over into the new data source.
|
||||||
|
auth.setRealName("Player");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import java.io.File;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,19 +41,17 @@ public class RakamakConverter implements Converter {
|
|||||||
@Override
|
@Override
|
||||||
// TODO ljacqu 20151229: Restructure this into smaller portions
|
// TODO ljacqu 20151229: Restructure this into smaller portions
|
||||||
public void execute(CommandSender sender) {
|
public void execute(CommandSender sender) {
|
||||||
boolean useIP = settings.getProperty(ConverterSettings.RAKAMAK_USE_IP);
|
boolean useIp = settings.getProperty(ConverterSettings.RAKAMAK_USE_IP);
|
||||||
String fileName = settings.getProperty(ConverterSettings.RAKAMAK_FILE_NAME);
|
String fileName = settings.getProperty(ConverterSettings.RAKAMAK_FILE_NAME);
|
||||||
String ipFileName = settings.getProperty(ConverterSettings.RAKAMAK_IP_FILE_NAME);
|
String ipFileName = settings.getProperty(ConverterSettings.RAKAMAK_IP_FILE_NAME);
|
||||||
File source = new File(pluginFolder, fileName);
|
File source = new File(pluginFolder, fileName);
|
||||||
File ipfiles = new File(pluginFolder, ipFileName);
|
File ipFiles = new File(pluginFolder, ipFileName);
|
||||||
HashMap<String, String> playerIP = new HashMap<>();
|
Map<String, String> playerIP = new HashMap<>();
|
||||||
HashMap<String, HashedPassword> playerPSW = new HashMap<>();
|
Map<String, HashedPassword> playerPassword = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
BufferedReader users;
|
BufferedReader ipFile = new BufferedReader(new FileReader(ipFiles));
|
||||||
BufferedReader ipFile;
|
|
||||||
ipFile = new BufferedReader(new FileReader(ipfiles));
|
|
||||||
String line;
|
String line;
|
||||||
if (useIP) {
|
if (useIp) {
|
||||||
String tempLine;
|
String tempLine;
|
||||||
while ((tempLine = ipFile.readLine()) != null) {
|
while ((tempLine = ipFile.readLine()) != null) {
|
||||||
if (tempLine.contains("=")) {
|
if (tempLine.contains("=")) {
|
||||||
@ -63,20 +62,20 @@ public class RakamakConverter implements Converter {
|
|||||||
}
|
}
|
||||||
ipFile.close();
|
ipFile.close();
|
||||||
|
|
||||||
users = new BufferedReader(new FileReader(source));
|
BufferedReader users = new BufferedReader(new FileReader(source));
|
||||||
while ((line = users.readLine()) != null) {
|
while ((line = users.readLine()) != null) {
|
||||||
if (line.contains("=")) {
|
if (line.contains("=")) {
|
||||||
String[] arguments = line.split("=");
|
String[] arguments = line.split("=");
|
||||||
HashedPassword hashedPassword = passwordSecurity.computeHash(arguments[1], arguments[0]);
|
HashedPassword hashedPassword = passwordSecurity.computeHash(arguments[1], arguments[0]);
|
||||||
playerPSW.put(arguments[0], hashedPassword);
|
playerPassword.put(arguments[0], hashedPassword);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
users.close();
|
users.close();
|
||||||
for (Entry<String, HashedPassword> m : playerPSW.entrySet()) {
|
for (Entry<String, HashedPassword> m : playerPassword.entrySet()) {
|
||||||
String playerName = m.getKey();
|
String playerName = m.getKey();
|
||||||
HashedPassword psw = playerPSW.get(playerName);
|
HashedPassword psw = playerPassword.get(playerName);
|
||||||
String ip = useIP ? playerIP.get(playerName) : "127.0.0.1";
|
String ip = useIp ? playerIP.get(playerName) : "127.0.0.1";
|
||||||
PlayerAuth auth = PlayerAuth.builder()
|
PlayerAuth auth = PlayerAuth.builder()
|
||||||
.name(playerName)
|
.name(playerName)
|
||||||
.realName(playerName)
|
.realName(playerName)
|
||||||
|
@ -6,7 +6,7 @@ import de.luricos.bukkit.xAuth.xAuth;
|
|||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public class xAuthConverter implements Converter {
|
|||||||
sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
|
sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
|
||||||
}
|
}
|
||||||
List<Integer> players = getXAuthPlayers();
|
List<Integer> players = getXAuthPlayers();
|
||||||
if (CollectionUtils.isEmpty(players)) {
|
if (Utils.isCollectionEmpty(players)) {
|
||||||
sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
|
sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package fr.xephi.authme.initialization;
|
|||||||
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.data.backup.LimboPlayerStorage;
|
import fr.xephi.authme.data.limbo.LimboPlayerStorage;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.service.PluginHookService;
|
import fr.xephi.authme.service.PluginHookService;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package fr.xephi.authme.initialization;
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
|
import ch.jalu.injector.exceptions.InjectorReflectionException;
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.message.Messages;
|
import fr.xephi.authme.message.Messages;
|
||||||
|
import org.bstats.Metrics;
|
||||||
import fr.xephi.authme.output.ConsoleFilter;
|
import fr.xephi.authme.output.ConsoleFilter;
|
||||||
import fr.xephi.authme.output.Log4JFilter;
|
import fr.xephi.authme.output.Log4JFilter;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
@ -18,10 +20,9 @@ import fr.xephi.authme.util.StringUtils;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.mcstats.Metrics;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.IOException;
|
import java.util.Optional;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE;
|
import static fr.xephi.authme.service.BukkitService.TICKS_PER_MINUTE;
|
||||||
@ -44,34 +45,28 @@ public class OnStartupTasks {
|
|||||||
OnStartupTasks() {
|
OnStartupTasks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends bstats metrics.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin instance
|
||||||
|
* @param settings the settings
|
||||||
|
*/
|
||||||
public static void sendMetrics(AuthMe plugin, Settings settings) {
|
public static void sendMetrics(AuthMe plugin, Settings settings) {
|
||||||
try {
|
|
||||||
final Metrics metrics = new Metrics(plugin);
|
final Metrics metrics = new Metrics(plugin);
|
||||||
|
|
||||||
final Metrics.Graph languageGraph = metrics.createGraph("Messages Language");
|
metrics.addCustomChart(new Metrics.SimplePie("messages_language") {
|
||||||
final String messagesLanguage = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
|
|
||||||
languageGraph.addPlotter(new Metrics.Plotter(messagesLanguage) {
|
|
||||||
@Override
|
@Override
|
||||||
public int getValue() {
|
public String getValue() {
|
||||||
return 1;
|
return settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final Metrics.Graph databaseBackend = metrics.createGraph("Database Backend");
|
metrics.addCustomChart(new Metrics.SimplePie("database_backend") {
|
||||||
final String dataSource = settings.getProperty(DatabaseSettings.BACKEND).toString();
|
|
||||||
databaseBackend.addPlotter(new Metrics.Plotter(dataSource) {
|
|
||||||
@Override
|
@Override
|
||||||
public int getValue() {
|
public String getValue() {
|
||||||
return 1;
|
return settings.getProperty(DatabaseSettings.BACKEND).toString();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,4 +119,23 @@ public class OnStartupTasks {
|
|||||||
}
|
}
|
||||||
}, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
|
}, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a hint to use the legacy AuthMe JAR if AuthMe could not be started
|
||||||
|
* because Gson was not found.
|
||||||
|
*
|
||||||
|
* @param e the exception to process
|
||||||
|
*/
|
||||||
|
public static void displayLegacyJarHint(Exception e) {
|
||||||
|
if (e instanceof InjectorReflectionException) {
|
||||||
|
Throwable causeOfCause = Optional.of(e)
|
||||||
|
.map(Throwable::getCause)
|
||||||
|
.map(Throwable::getCause).orElse(null);
|
||||||
|
if (causeOfCause instanceof NoClassDefFoundError
|
||||||
|
&& "Lcom/google/gson/Gson;".equals(causeOfCause.getMessage())) {
|
||||||
|
ConsoleLogger.warning("YOU MUST DOWNLOAD THE LEGACY JAR TO USE AUTHME ON YOUR SERVER");
|
||||||
|
ConsoleLogger.warning("Get authme-legacy.jar from http://ci.xephi.fr/job/AuthMeReloaded/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package fr.xephi.authme.initialization.factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injectable factory that creates new instances of a certain type.
|
||||||
|
*
|
||||||
|
* @param <P> the parent type to which the factory is limited to
|
||||||
|
*/
|
||||||
|
public interface Factory<P> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the given class.
|
||||||
|
*
|
||||||
|
* @param clazz the class to instantiate
|
||||||
|
* @param <C> the class type
|
||||||
|
* @return new instance of the class
|
||||||
|
*/
|
||||||
|
<C extends P> C newInstance(Class<C> clazz);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package fr.xephi.authme.initialization.factory;
|
||||||
|
|
||||||
|
import ch.jalu.injector.Injector;
|
||||||
|
import ch.jalu.injector.context.ResolvedInstantiationContext;
|
||||||
|
import ch.jalu.injector.handlers.dependency.DependencyHandler;
|
||||||
|
import ch.jalu.injector.handlers.instantiation.DependencyDescription;
|
||||||
|
import ch.jalu.injector.utils.ReflectionUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency handler that builds {@link Factory} objects.
|
||||||
|
*/
|
||||||
|
public class FactoryDependencyHandler implements DependencyHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveValue(ResolvedInstantiationContext<?> context, DependencyDescription dependencyDescription) {
|
||||||
|
if (dependencyDescription.getType() == Factory.class) {
|
||||||
|
Class<?> genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType());
|
||||||
|
if (genericType == null) {
|
||||||
|
throw new IllegalStateException("Factory fields must have concrete generic type. " +
|
||||||
|
"Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FactoryImpl<>(genericType, context.getInjector());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class FactoryImpl<P> implements Factory<P> {
|
||||||
|
|
||||||
|
private final Injector injector;
|
||||||
|
private final Class<P> parentClass;
|
||||||
|
|
||||||
|
FactoryImpl(Class<P> parentClass, Injector injector) {
|
||||||
|
this.parentClass = parentClass;
|
||||||
|
this.injector = injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <C extends P> C newInstance(Class<C> clazz) {
|
||||||
|
if (parentClass.isAssignableFrom(clazz)) {
|
||||||
|
return injector.newInstance(clazz);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(clazz + " not child of " + parentClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package fr.xephi.authme.listener.protocollib;
|
package fr.xephi.authme.listener.protocollib;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
@ -46,7 +47,7 @@ class InventoryPacketAdapter extends PacketAdapter {
|
|||||||
private static final int MAIN_SIZE = 27;
|
private static final int MAIN_SIZE = 27;
|
||||||
private static final int HOTBAR_SIZE = 9;
|
private static final int HOTBAR_SIZE = 9;
|
||||||
|
|
||||||
public InventoryPacketAdapter(AuthMe plugin) {
|
InventoryPacketAdapter(AuthMe plugin) {
|
||||||
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
|
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
|
|||||||
|
|
||||||
class TabCompletePacketAdapter extends PacketAdapter {
|
class TabCompletePacketAdapter extends PacketAdapter {
|
||||||
|
|
||||||
public TabCompletePacketAdapter(AuthMe plugin) {
|
TabCompletePacketAdapter(AuthMe plugin) {
|
||||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
125
src/main/java/fr/xephi/authme/mail/EmailService.java
Normal file
125
src/main/java/fr/xephi/authme/mail/EmailService.java
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package fr.xephi.authme.mail;
|
||||||
|
|
||||||
|
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.util.FileUtils;
|
||||||
|
import org.apache.commons.mail.EmailException;
|
||||||
|
import org.apache.commons.mail.HtmlEmail;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
|
||||||
|
import javax.activation.DataSource;
|
||||||
|
import javax.activation.FileDataSource;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates emails and sends them.
|
||||||
|
*/
|
||||||
|
public class EmailService {
|
||||||
|
|
||||||
|
private final File dataFolder;
|
||||||
|
private final String serverName;
|
||||||
|
private final Settings settings;
|
||||||
|
private final SendMailSSL sendMailSSL;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
EmailService(@DataFolder File dataFolder, Server server, Settings settings, SendMailSSL sendMailSSL) {
|
||||||
|
this.dataFolder = dataFolder;
|
||||||
|
this.serverName = server.getServerName();
|
||||||
|
this.settings = settings;
|
||||||
|
this.sendMailSSL = sendMailSSL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAllInformation() {
|
||||||
|
return sendMailSSL.hasAllInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an email to the user with his new password.
|
||||||
|
*
|
||||||
|
* @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 boolean sendPasswordMail(String name, String mailAddress, String newPass) {
|
||||||
|
if (!hasAllInformation()) {
|
||||||
|
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlEmail email;
|
||||||
|
try {
|
||||||
|
email = sendMailSSL.initializeMail(mailAddress);
|
||||||
|
} catch (EmailException e) {
|
||||||
|
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = sendMailSSL.sendEmail(mailText, email);
|
||||||
|
FileUtils.delete(file);
|
||||||
|
return couldSendEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sendRecoveryCode(String name, String email, String code) {
|
||||||
|
HtmlEmail htmlEmail;
|
||||||
|
try {
|
||||||
|
htmlEmail = sendMailSSL.initializeMail(email);
|
||||||
|
} catch (EmailException e) {
|
||||||
|
ConsoleLogger.logException("Failed to create email for recovery code:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
|
||||||
|
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
|
||||||
|
return sendMailSSL.sendEmail(message, htmlEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File generateImage(String name, String newPass) throws IOException {
|
||||||
|
ImageGenerator gen = new ImageGenerator(newPass);
|
||||||
|
File file = new File(dataFolder, name + "_new_pass.jpg");
|
||||||
|
ImageIO.write(gen.generateImage(), "jpg", file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content)
|
||||||
|
throws EmailException {
|
||||||
|
DataSource source = new FileDataSource(image);
|
||||||
|
String tag = email.embed(source, image.getName());
|
||||||
|
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
|
||||||
|
return mailText
|
||||||
|
.replace("<playername />", name)
|
||||||
|
.replace("<servername />", serverName)
|
||||||
|
.replace("<generatedpass />", newPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
|
||||||
|
return mailText
|
||||||
|
.replace("<playername />", name)
|
||||||
|
.replace("<servername />", serverName)
|
||||||
|
.replace("<recoverycode />", code)
|
||||||
|
.replace("<hoursvalid />", String.valueOf(hoursValid));
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,19 @@
|
|||||||
package fr.xephi.authme.mail;
|
package fr.xephi.authme.mail;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.output.LogLevel;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import fr.xephi.authme.util.FileUtils;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.apache.commons.mail.EmailConstants;
|
import org.apache.commons.mail.EmailConstants;
|
||||||
import org.apache.commons.mail.EmailException;
|
import org.apache.commons.mail.EmailException;
|
||||||
import org.apache.commons.mail.HtmlEmail;
|
import org.apache.commons.mail.HtmlEmail;
|
||||||
import org.bukkit.Server;
|
|
||||||
|
|
||||||
import javax.activation.CommandMap;
|
import javax.activation.CommandMap;
|
||||||
import javax.activation.DataSource;
|
|
||||||
import javax.activation.FileDataSource;
|
|
||||||
import javax.activation.MailcapCommandMap;
|
import javax.activation.MailcapCommandMap;
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -34,16 +26,8 @@ import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
|
|||||||
*/
|
*/
|
||||||
public class SendMailSSL {
|
public class SendMailSSL {
|
||||||
|
|
||||||
private final File dataFolder;
|
|
||||||
private final String serverName;
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SendMailSSL(@DataFolder File dataFolder, Server server, Settings settings) {
|
private Settings settings;
|
||||||
this.dataFolder = dataFolder;
|
|
||||||
this.serverName = server.getServerName();
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether all necessary settings are set for sending mails.
|
* Returns whether all necessary settings are set for sending mails.
|
||||||
@ -55,76 +39,7 @@ public class SendMailSSL {
|
|||||||
&& !settings.getProperty(MAIL_PASSWORD).isEmpty();
|
&& !settings.getProperty(MAIL_PASSWORD).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
||||||
* Sends an email to the user with his new password.
|
|
||||||
*
|
|
||||||
* @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 boolean sendPasswordMail(String name, String mailAddress, String newPass) {
|
|
||||||
if (!hasAllInformation()) {
|
|
||||||
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
HtmlEmail email;
|
|
||||||
try {
|
|
||||||
email = initializeMail(mailAddress);
|
|
||||||
} catch (EmailException e) {
|
|
||||||
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
|
|
||||||
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID));
|
|
||||||
return sendEmail(message, htmlEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File generateImage(String name, String newPass) throws IOException {
|
|
||||||
ImageGenerator gen = new ImageGenerator(newPass);
|
|
||||||
File file = new File(dataFolder, name + "_new_pass.jpg");
|
|
||||||
ImageIO.write(gen.generateImage(), "jpg", file);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content)
|
|
||||||
throws EmailException {
|
|
||||||
DataSource source = new FileDataSource(image);
|
|
||||||
String tag = email.embed(source, image.getName());
|
|
||||||
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
|
||||||
String senderMail = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_ADDRESS))
|
String senderMail = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_ADDRESS))
|
||||||
? settings.getProperty(EmailSettings.MAIL_ACCOUNT)
|
? settings.getProperty(EmailSettings.MAIL_ACCOUNT)
|
||||||
: settings.getProperty(EmailSettings.MAIL_ADDRESS);
|
: settings.getProperty(EmailSettings.MAIL_ADDRESS);
|
||||||
@ -143,13 +58,15 @@ public class SendMailSSL {
|
|||||||
email.setFrom(senderMail, senderName);
|
email.setFrom(senderMail, senderName);
|
||||||
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
||||||
email.setAuthentication(settings.getProperty(EmailSettings.MAIL_ACCOUNT), mailPassword);
|
email.setAuthentication(settings.getProperty(EmailSettings.MAIL_ACCOUNT), mailPassword);
|
||||||
|
if (settings.getProperty(PluginSettings.LOG_LEVEL).includes(LogLevel.DEBUG)) {
|
||||||
|
email.setDebug(true);
|
||||||
|
}
|
||||||
|
|
||||||
setPropertiesForPort(email, port);
|
setPropertiesForPort(email, port);
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
public boolean sendEmail(String content, HtmlEmail email) {
|
||||||
boolean sendEmail(String content, HtmlEmail email) {
|
|
||||||
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader());
|
Thread.currentThread().setContextClassLoader(SendMailSSL.class.getClassLoader());
|
||||||
// Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative
|
// 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
|
// cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type
|
||||||
@ -176,21 +93,6 @@ public class SendMailSSL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String replaceTagsForPasswordMail(String mailText, String name, String newPass) {
|
|
||||||
return mailText
|
|
||||||
.replace("<playername />", name)
|
|
||||||
.replace("<servername />", serverName)
|
|
||||||
.replace("<generatedpass />", newPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid) {
|
|
||||||
return mailText
|
|
||||||
.replace("<playername />", name)
|
|
||||||
.replace("<servername />", serverName)
|
|
||||||
.replace("<recoverycode />", code)
|
|
||||||
.replace("<hoursvalid />", String.valueOf(hoursValid));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
|
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
|
||||||
switch (port) {
|
switch (port) {
|
||||||
case 587:
|
case 587:
|
||||||
@ -214,8 +116,10 @@ public class SendMailSSL {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 25:
|
case 25:
|
||||||
|
if (settings.getProperty(EmailSettings.PORT25_USE_TLS)) {
|
||||||
email.setStartTLSEnabled(true);
|
email.setStartTLSEnabled(true);
|
||||||
email.setSSLCheckServerIdentity(true);
|
email.setSSLCheckServerIdentity(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 465:
|
case 465:
|
||||||
email.setSslSmtpPort(Integer.toString(port));
|
email.setSslSmtpPort(Integer.toString(port));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package fr.xephi.authme.message;
|
package fr.xephi.authme.message;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ public class MessageFileHandler {
|
|||||||
// regular file
|
// regular file
|
||||||
private final String filename;
|
private final String filename;
|
||||||
private final FileConfiguration configuration;
|
private final FileConfiguration configuration;
|
||||||
|
private final String updateAddition;
|
||||||
// default file
|
// default file
|
||||||
private final String defaultFile;
|
private final String defaultFile;
|
||||||
private FileConfiguration defaultConfiguration;
|
private FileConfiguration defaultConfiguration;
|
||||||
@ -25,11 +27,15 @@ public class MessageFileHandler {
|
|||||||
*
|
*
|
||||||
* @param file the file to use for messages
|
* @param file the file to use for messages
|
||||||
* @param defaultFile the default file from the JAR to use if no message is found
|
* @param defaultFile the default file from the JAR to use if no message is found
|
||||||
|
* @param updateCommand command to update the messages file (nullable) to show in error messages
|
||||||
*/
|
*/
|
||||||
public MessageFileHandler(File file, String defaultFile) {
|
public MessageFileHandler(File file, String defaultFile, String updateCommand) {
|
||||||
this.filename = file.getName();
|
this.filename = file.getName();
|
||||||
this.configuration = YamlConfiguration.loadConfiguration(file);
|
this.configuration = YamlConfiguration.loadConfiguration(file);
|
||||||
this.defaultFile = defaultFile;
|
this.defaultFile = defaultFile;
|
||||||
|
this.updateAddition = updateCommand == null
|
||||||
|
? ""
|
||||||
|
: " (or run " + updateCommand + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +59,7 @@ public class MessageFileHandler {
|
|||||||
|
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
ConsoleLogger.warning("Error getting message with key '" + key + "'. "
|
ConsoleLogger.warning("Error getting message with key '" + key + "'. "
|
||||||
+ "Please update your config file '" + filename + "' (or run /authme messages)");
|
+ "Please update your config file '" + filename + "'" + updateAddition);
|
||||||
return getDefault(key);
|
return getDefault(key);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
@ -78,7 +84,7 @@ public class MessageFileHandler {
|
|||||||
*/
|
*/
|
||||||
private String getDefault(String key) {
|
private String getDefault(String key) {
|
||||||
if (defaultConfiguration == null) {
|
if (defaultConfiguration == null) {
|
||||||
InputStream stream = MessageFileHandler.class.getClassLoader().getResourceAsStream(defaultFile);
|
InputStream stream = FileUtils.getResourceFromJar(defaultFile);
|
||||||
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
|
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
|
||||||
}
|
}
|
||||||
String message = defaultConfiguration.getString(key);
|
String message = defaultConfiguration.getString(key);
|
||||||
|
@ -36,10 +36,23 @@ public class MessageFileHandlerProvider {
|
|||||||
* @return the message file handler
|
* @return the message file handler
|
||||||
*/
|
*/
|
||||||
public MessageFileHandler initializeHandler(Function<String, String> pathBuilder) {
|
public MessageFileHandler initializeHandler(Function<String, String> pathBuilder) {
|
||||||
|
return initializeHandler(pathBuilder, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a message file handler with the messages file of the configured language.
|
||||||
|
* Ensures beforehand that the messages file exists or creates it otherwise.
|
||||||
|
*
|
||||||
|
* @param pathBuilder function taking the configured language code as argument and returning the messages file
|
||||||
|
* @param updateCommand command to run to update the languages file (nullable)
|
||||||
|
* @return the message file handler
|
||||||
|
*/
|
||||||
|
public MessageFileHandler initializeHandler(Function<String, String> pathBuilder, String updateCommand) {
|
||||||
String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
|
String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
|
||||||
return new MessageFileHandler(
|
return new MessageFileHandler(
|
||||||
initializeFile(language, pathBuilder),
|
initializeFile(language, pathBuilder),
|
||||||
pathBuilder.apply(DEFAULT_LANGUAGE));
|
pathBuilder.apply(DEFAULT_LANGUAGE),
|
||||||
|
updateCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +66,8 @@ public class MessageFileHandlerProvider {
|
|||||||
File initializeFile(String language, Function<String, String> pathBuilder) {
|
File initializeFile(String language, Function<String, String> pathBuilder) {
|
||||||
String filePath = pathBuilder.apply(language);
|
String filePath = pathBuilder.apply(language);
|
||||||
File file = new File(dataFolder, filePath);
|
File file = new File(dataFolder, filePath);
|
||||||
if (FileUtils.copyFileFromResource(file, filePath)) {
|
// Check that JAR file exists to avoid logging an error
|
||||||
|
if (FileUtils.getResourceFromJar(filePath) != null && FileUtils.copyFileFromResource(file, filePath)) {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ public enum MessageKey {
|
|||||||
/** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */
|
/** AntiBot protection mode is enabled! You have to wait some minutes before joining the server. */
|
||||||
KICK_ANTIBOT("kick_antibot"),
|
KICK_ANTIBOT("kick_antibot"),
|
||||||
|
|
||||||
/** Can't find the requested user in the database! */
|
/** This user isn't registered! */
|
||||||
UNKNOWN_USER("unknown_user"),
|
UNKNOWN_USER("unknown_user"),
|
||||||
|
|
||||||
/** Your quit location was unsafe, you have been teleported to the world's spawnpoint. */
|
/** Your quit location was unsafe, you have been teleported to the world's spawnpoint. */
|
||||||
@ -26,7 +26,7 @@ public enum MessageKey {
|
|||||||
/** You're not logged in! */
|
/** You're not logged in! */
|
||||||
NOT_LOGGED_IN("not_logged_in"),
|
NOT_LOGGED_IN("not_logged_in"),
|
||||||
|
|
||||||
/** Usage: /login <password> */
|
/** Usage: /login <password> */
|
||||||
USAGE_LOGIN("usage_log"),
|
USAGE_LOGIN("usage_log"),
|
||||||
|
|
||||||
/** Wrong password! */
|
/** Wrong password! */
|
||||||
@ -56,19 +56,19 @@ public enum MessageKey {
|
|||||||
/** An unexpected error occurred, please contact an administrator! */
|
/** An unexpected error occurred, please contact an administrator! */
|
||||||
ERROR("error"),
|
ERROR("error"),
|
||||||
|
|
||||||
/** Please, login with the command "/login <password>" */
|
/** Please, login with the command: /login <password> */
|
||||||
LOGIN_MESSAGE("login_msg"),
|
LOGIN_MESSAGE("login_msg"),
|
||||||
|
|
||||||
/** Please, register to the server with the command "/register <password> <ConfirmPassword>" */
|
/** Please, register to the server with the command: /register <password> <ConfirmPassword> */
|
||||||
REGISTER_MESSAGE("reg_msg"),
|
REGISTER_MESSAGE("reg_msg"),
|
||||||
|
|
||||||
/** You have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection! */
|
/** You have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection! */
|
||||||
MAX_REGISTER_EXCEEDED("max_reg", "%max_acc", "%reg_count", "%reg_names"),
|
MAX_REGISTER_EXCEEDED("max_reg", "%max_acc", "%reg_count", "%reg_names"),
|
||||||
|
|
||||||
/** Usage: /register <password> <ConfirmPassword> */
|
/** Usage: /register <password> <ConfirmPassword> */
|
||||||
USAGE_REGISTER("usage_reg"),
|
USAGE_REGISTER("usage_reg"),
|
||||||
|
|
||||||
/** Usage: /unregister <password> */
|
/** Usage: /unregister <password> */
|
||||||
USAGE_UNREGISTER("usage_unreg"),
|
USAGE_UNREGISTER("usage_unreg"),
|
||||||
|
|
||||||
/** Password changed successfully! */
|
/** Password changed successfully! */
|
||||||
@ -95,7 +95,7 @@ public enum MessageKey {
|
|||||||
/** You're already logged in! */
|
/** You're already logged in! */
|
||||||
ALREADY_LOGGED_IN_ERROR("logged_in"),
|
ALREADY_LOGGED_IN_ERROR("logged_in"),
|
||||||
|
|
||||||
/** Logged-out successfully! */
|
/** Logged out successfully! */
|
||||||
LOGOUT_SUCCESS("logout"),
|
LOGOUT_SUCCESS("logout"),
|
||||||
|
|
||||||
/** The same username is already playing on the server! */
|
/** The same username is already playing on the server! */
|
||||||
@ -113,7 +113,7 @@ public enum MessageKey {
|
|||||||
/** Login timeout exceeded, you have been kicked from the server, please try again! */
|
/** Login timeout exceeded, you have been kicked from the server, please try again! */
|
||||||
LOGIN_TIMEOUT_ERROR("timeout"),
|
LOGIN_TIMEOUT_ERROR("timeout"),
|
||||||
|
|
||||||
/** Usage: /changepassword <oldPassword> <newPassword> */
|
/** Usage: /changepassword <oldPassword> <newPassword> */
|
||||||
USAGE_CHANGE_PASSWORD("usage_changepassword"),
|
USAGE_CHANGE_PASSWORD("usage_changepassword"),
|
||||||
|
|
||||||
/** Your username is either too short or too long! */
|
/** Your username is either too short or too long! */
|
||||||
@ -122,13 +122,13 @@ public enum MessageKey {
|
|||||||
/** Your username contains illegal characters. Allowed chars: REG_EX */
|
/** Your username contains illegal characters. Allowed chars: REG_EX */
|
||||||
INVALID_NAME_CHARACTERS("regex", "REG_EX"),
|
INVALID_NAME_CHARACTERS("regex", "REG_EX"),
|
||||||
|
|
||||||
/** Please add your email to your account with the command "/email add <yourEmail> <confirmEmail>" */
|
/** Please add your email to your account with the command: /email add <yourEmail> <confirmEmail> */
|
||||||
ADD_EMAIL_MESSAGE("add_email"),
|
ADD_EMAIL_MESSAGE("add_email"),
|
||||||
|
|
||||||
/** Forgot your password? Please use the command "/email recovery <yourEmail>" */
|
/** Forgot your password? Please use the command: /email recovery <yourEmail> */
|
||||||
FORGOT_PASSWORD_MESSAGE("recovery_email"),
|
FORGOT_PASSWORD_MESSAGE("recovery_email"),
|
||||||
|
|
||||||
/** To login you have to solve a captcha code, please use the command "/captcha <theCaptcha>" */
|
/** To login you have to solve a captcha code, please use the command: /captcha <theCaptcha> */
|
||||||
USAGE_CAPTCHA("usage_captcha", "<theCaptcha>"),
|
USAGE_CAPTCHA("usage_captcha", "<theCaptcha>"),
|
||||||
|
|
||||||
/** Wrong captcha, please type "/captcha THE_CAPTCHA" into the chat! */
|
/** Wrong captcha, please type "/captcha THE_CAPTCHA" into the chat! */
|
||||||
@ -143,13 +143,13 @@ public enum MessageKey {
|
|||||||
/** The server is full, try again later! */
|
/** The server is full, try again later! */
|
||||||
KICK_FULL_SERVER("kick_fullserver"),
|
KICK_FULL_SERVER("kick_fullserver"),
|
||||||
|
|
||||||
/** Usage: /email add <email> <confirmEmail> */
|
/** Usage: /email add <email> <confirmEmail> */
|
||||||
USAGE_ADD_EMAIL("usage_email_add"),
|
USAGE_ADD_EMAIL("usage_email_add"),
|
||||||
|
|
||||||
/** Usage: /email change <oldEmail> <newEmail> */
|
/** Usage: /email change <oldEmail> <newEmail> */
|
||||||
USAGE_CHANGE_EMAIL("usage_email_change"),
|
USAGE_CHANGE_EMAIL("usage_email_change"),
|
||||||
|
|
||||||
/** Usage: /email recovery <Email> */
|
/** Usage: /email recovery <Email> */
|
||||||
USAGE_RECOVER_EMAIL("usage_email_recovery"),
|
USAGE_RECOVER_EMAIL("usage_email_recovery"),
|
||||||
|
|
||||||
/** Invalid new email, try again! */
|
/** Invalid new email, try again! */
|
||||||
@ -224,8 +224,36 @@ public enum MessageKey {
|
|||||||
/** A recovery code to reset your password has been sent to your email. */
|
/** A recovery code to reset your password has been sent to your email. */
|
||||||
RECOVERY_CODE_SENT("recovery_code_sent"),
|
RECOVERY_CODE_SENT("recovery_code_sent"),
|
||||||
|
|
||||||
/** The recovery code is not correct! Use /email recovery [email] to generate a new one */
|
/** The recovery code is not correct! Use "/email recovery [email]" to generate a new one */
|
||||||
INCORRECT_RECOVERY_CODE("recovery_code_incorrect");
|
INCORRECT_RECOVERY_CODE("recovery_code_incorrect"),
|
||||||
|
|
||||||
|
/** An email was already sent recently. You must wait %time before you can send a new one. */
|
||||||
|
EMAIL_COOLDOWN_ERROR("email_cooldown_error", "%time"),
|
||||||
|
|
||||||
|
/** second */
|
||||||
|
SECOND("second"),
|
||||||
|
|
||||||
|
/** seconds */
|
||||||
|
SECONDS("seconds"),
|
||||||
|
|
||||||
|
/** minute */
|
||||||
|
MINUTE("minute"),
|
||||||
|
|
||||||
|
/** minutes */
|
||||||
|
MINUTES("minutes"),
|
||||||
|
|
||||||
|
/** hour */
|
||||||
|
HOUR("hour"),
|
||||||
|
|
||||||
|
/** hours */
|
||||||
|
HOURS("hours"),
|
||||||
|
|
||||||
|
/** day */
|
||||||
|
DAY("day"),
|
||||||
|
|
||||||
|
/** days */
|
||||||
|
DAYS("days");
|
||||||
|
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
private String[] tags;
|
private String[] tags;
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package fr.xephi.authme.message;
|
package fr.xephi.authme.message;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.util.expiring.Duration;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for retrieving and sending translatable messages to players.
|
* Class for retrieving and sending translatable messages to players.
|
||||||
@ -15,6 +19,20 @@ public class Messages implements Reloadable {
|
|||||||
// Custom Authme tag replaced to new line
|
// Custom Authme tag replaced to new line
|
||||||
private static final String NEWLINE_TAG = "%nl%";
|
private static final String NEWLINE_TAG = "%nl%";
|
||||||
|
|
||||||
|
/** Contains the keys of the singular messages for time units. */
|
||||||
|
private static final Map<TimeUnit, MessageKey> TIME_UNIT_SINGULARS = ImmutableMap.<TimeUnit, MessageKey>builder()
|
||||||
|
.put(TimeUnit.SECONDS, MessageKey.SECOND)
|
||||||
|
.put(TimeUnit.MINUTES, MessageKey.MINUTE)
|
||||||
|
.put(TimeUnit.HOURS, MessageKey.HOUR)
|
||||||
|
.put(TimeUnit.DAYS, MessageKey.DAY).build();
|
||||||
|
|
||||||
|
/** Contains the keys of the plural messages for time units. */
|
||||||
|
private static final Map<TimeUnit, MessageKey> TIME_UNIT_PLURALS = ImmutableMap.<TimeUnit, MessageKey>builder()
|
||||||
|
.put(TimeUnit.SECONDS, MessageKey.SECONDS)
|
||||||
|
.put(TimeUnit.MINUTES, MessageKey.MINUTES)
|
||||||
|
.put(TimeUnit.HOURS, MessageKey.HOURS)
|
||||||
|
.put(TimeUnit.DAYS, MessageKey.DAYS).build();
|
||||||
|
|
||||||
private final MessageFileHandlerProvider messageFileHandlerProvider;
|
private final MessageFileHandlerProvider messageFileHandlerProvider;
|
||||||
private MessageFileHandler messageFileHandler;
|
private MessageFileHandler messageFileHandler;
|
||||||
|
|
||||||
@ -71,6 +89,22 @@ public class Messages implements Reloadable {
|
|||||||
return message.split("\n");
|
return message.split("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the textual representation for the given duration.
|
||||||
|
* Note that this class only supports the time units days, hour, minutes and seconds.
|
||||||
|
*
|
||||||
|
* @param duration the duration to build a text of
|
||||||
|
* @return text of the duration
|
||||||
|
*/
|
||||||
|
public String formatDuration(Duration duration) {
|
||||||
|
long value = duration.getDuration();
|
||||||
|
MessageKey timeUnitKey = value == 1
|
||||||
|
? TIME_UNIT_SINGULARS.get(duration.getTimeUnit())
|
||||||
|
: TIME_UNIT_PLURALS.get(duration.getTimeUnit());
|
||||||
|
|
||||||
|
return value + " " + retrieveMessage(timeUnitKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the message from the text file.
|
* Retrieve the message from the text file.
|
||||||
*
|
*
|
||||||
@ -107,7 +141,7 @@ public class Messages implements Reloadable {
|
|||||||
@Override
|
@Override
|
||||||
public void reload() {
|
public void reload() {
|
||||||
this.messageFileHandler = messageFileHandlerProvider
|
this.messageFileHandler = messageFileHandlerProvider
|
||||||
.initializeHandler(lang -> "messages/messages_" + lang + ".yml");
|
.initializeHandler(lang -> "messages/messages_" + lang + ".yml", "/authme messages");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String formatMessage(String message) {
|
private static String formatMessage(String message) {
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package fr.xephi.authme.output;
|
package fr.xephi.authme.output;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service class for the log filters.
|
* Service class for the log filters.
|
||||||
*/
|
*/
|
||||||
public final class LogFilterHelper {
|
final class LogFilterHelper {
|
||||||
|
|
||||||
private static final String ISSUED_COMMAND_TEXT = "issued server command:";
|
private static final String ISSUED_COMMAND_TEXT = "issued server command:";
|
||||||
|
|
||||||
private static final String[] COMMANDS_TO_SKIP = {"/login ", "/l ", "/reg ", "/changepassword ",
|
@VisibleForTesting
|
||||||
"/unregister ", "/authme register ", "/authme changepassword ", "/authme reg ", "/authme cp ",
|
static final List<String> COMMANDS_TO_SKIP = withAndWithoutAuthMePrefix(
|
||||||
"/register "};
|
"/login ", "/l ", "/log ", "/register ", "/reg ", "/unregister ", "/unreg ",
|
||||||
|
"/changepassword ", "/cp ", "/changepass ", "/authme register ", "/authme reg ", "/authme r ",
|
||||||
|
"/authme changepassword ", "/authme password ", "/authme changepass ", "/authme cp ");
|
||||||
|
|
||||||
private LogFilterHelper() {
|
private LogFilterHelper() {
|
||||||
// Util class
|
// Util class
|
||||||
@ -24,11 +31,20 @@ public final class LogFilterHelper {
|
|||||||
*
|
*
|
||||||
* @return True if it is a sensitive AuthMe command, false otherwise
|
* @return True if it is a sensitive AuthMe command, false otherwise
|
||||||
*/
|
*/
|
||||||
public static boolean isSensitiveAuthMeCommand(String message) {
|
static boolean isSensitiveAuthMeCommand(String message) {
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String lowerMessage = message.toLowerCase();
|
String lowerMessage = message.toLowerCase();
|
||||||
return lowerMessage.contains(ISSUED_COMMAND_TEXT) && StringUtils.containsAny(lowerMessage, COMMANDS_TO_SKIP);
|
return lowerMessage.contains(ISSUED_COMMAND_TEXT) && StringUtils.containsAny(lowerMessage, COMMANDS_TO_SKIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<String> withAndWithoutAuthMePrefix(String... commands) {
|
||||||
|
List<String> commandList = new ArrayList<>(commands.length * 2);
|
||||||
|
for (String command : commands) {
|
||||||
|
commandList.add(command);
|
||||||
|
commandList.add(command.substring(0, 1) + "authme:" + command.substring(1));
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(commandList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,24 @@ import fr.xephi.authme.data.limbo.LimboCache;
|
|||||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Arrays;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the permission group according to the auth status of the player and the configuration.
|
* Changes the permission group according to the auth status of the player and the configuration.
|
||||||
|
* <p>
|
||||||
|
* If this feature is enabled, the <i>primary permissions group</i> of a player is replaced until he has
|
||||||
|
* logged in. Some permission plugins have a notion of a primary group; for other permission plugins the
|
||||||
|
* first group is simply taken.
|
||||||
|
* <p>
|
||||||
|
* The groups that are used as replacement until the player logs in is configurable and depends on if
|
||||||
|
* the player is registered or not. Note that some (all?) permission systems require the group to actually
|
||||||
|
* exist for the replacement to take place. Furthermore, since some permission groups require that players
|
||||||
|
* be in at least one group, this will mean that the player is not removed from his primary group.
|
||||||
*/
|
*/
|
||||||
public class AuthGroupHandler implements Reloadable {
|
public class AuthGroupHandler implements Reloadable {
|
||||||
|
|
||||||
@ -28,7 +35,6 @@ public class AuthGroupHandler implements Reloadable {
|
|||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboCache limboCache;
|
||||||
|
|
||||||
private String unloggedInGroup;
|
|
||||||
private String unregisteredGroup;
|
private String unregisteredGroup;
|
||||||
private String registeredGroup;
|
private String registeredGroup;
|
||||||
|
|
||||||
@ -36,15 +42,53 @@ public class AuthGroupHandler implements Reloadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the group of a player, by its AuthMe group type.
|
* Sets the group of a player by its authentication status.
|
||||||
*
|
*
|
||||||
* @param player The player.
|
* @param player the player
|
||||||
* @param group The group type.
|
* @param groupType the group type
|
||||||
*
|
|
||||||
* @return True if succeeded, false otherwise. False is also returned if groups aren't supported
|
|
||||||
* with the current permissions system.
|
|
||||||
*/
|
*/
|
||||||
public boolean setGroup(Player player, AuthGroupType group) {
|
public void setGroup(Player player, AuthGroupType groupType) {
|
||||||
|
if (!useAuthGroups()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String primaryGroup = Optional
|
||||||
|
.ofNullable(limboCache.getPlayerData(player.getName()))
|
||||||
|
.map(LimboPlayer::getGroup)
|
||||||
|
.orElse("");
|
||||||
|
|
||||||
|
switch (groupType) {
|
||||||
|
// Implementation note: some permission systems don't support players not being in any group,
|
||||||
|
// so add the new group before removing the old ones
|
||||||
|
case UNREGISTERED:
|
||||||
|
permissionsManager.addGroup(player, unregisteredGroup);
|
||||||
|
permissionsManager.removeGroups(player, registeredGroup, primaryGroup);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REGISTERED_UNAUTHENTICATED:
|
||||||
|
permissionsManager.addGroup(player, registeredGroup);
|
||||||
|
permissionsManager.removeGroups(player, unregisteredGroup, primaryGroup);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOGGED_IN:
|
||||||
|
permissionsManager.addGroup(player, primaryGroup);
|
||||||
|
permissionsManager.removeGroups(player, unregisteredGroup, registeredGroup);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Encountered unhandled auth group type '" + groupType + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleLogger.debug(
|
||||||
|
() -> player.getName() + " changed to " + groupType + ": has groups " + permissionsManager.getGroups(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the auth permissions group function should be used.
|
||||||
|
*
|
||||||
|
* @return true if should be used, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean useAuthGroups() {
|
||||||
// Check whether the permissions check is enabled
|
// Check whether the permissions check is enabled
|
||||||
if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
||||||
return false;
|
return false;
|
||||||
@ -55,72 +99,14 @@ public class AuthGroupHandler implements Reloadable {
|
|||||||
ConsoleLogger.warning("The current permissions system doesn't have group support, unable to set group!");
|
ConsoleLogger.warning("The current permissions system doesn't have group support, unable to set group!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
switch (group) {
|
|
||||||
case UNREGISTERED:
|
|
||||||
// Remove the other group type groups, set the current group
|
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(registeredGroup, unloggedInGroup));
|
|
||||||
return permissionsManager.addGroup(player, unregisteredGroup);
|
|
||||||
|
|
||||||
case REGISTERED:
|
|
||||||
// Remove the other group type groups, set the current group
|
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, unloggedInGroup));
|
|
||||||
return permissionsManager.addGroup(player, registeredGroup);
|
|
||||||
|
|
||||||
case NOT_LOGGED_IN:
|
|
||||||
// Remove the other group type groups, set the current group
|
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup));
|
|
||||||
return permissionsManager.addGroup(player, unloggedInGroup);
|
|
||||||
|
|
||||||
case LOGGED_IN:
|
|
||||||
// Get the player data
|
|
||||||
LimboPlayer data = limboCache.getPlayerData(player.getName().toLowerCase());
|
|
||||||
if (data == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the players group
|
|
||||||
String realGroup = data.getGroup();
|
|
||||||
|
|
||||||
// Remove the other group types groups, set the real group
|
|
||||||
permissionsManager.removeGroups(player,
|
|
||||||
Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup)
|
|
||||||
);
|
|
||||||
return permissionsManager.addGroup(player, realGroup);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: This method requires better explanation.
|
|
||||||
* <p>
|
|
||||||
* Set the normal group of a player.
|
|
||||||
*
|
|
||||||
* @param player The player.
|
|
||||||
* @param group The normal group.
|
|
||||||
*
|
|
||||||
* @return True on success, false on failure.
|
|
||||||
*/
|
|
||||||
public boolean addNormal(Player player, String group) {
|
|
||||||
// Check whether the permissions check is enabled
|
|
||||||
if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove old groups
|
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup));
|
|
||||||
|
|
||||||
// Add the normal group, return the result
|
|
||||||
return permissionsManager.addGroup(player, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void reload() {
|
public void reload() {
|
||||||
unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
|
unregisteredGroup = settings.getProperty(PluginSettings.UNREGISTERED_GROUP);
|
||||||
unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);
|
registeredGroup = settings.getProperty(PluginSettings.REGISTERED_GROUP);
|
||||||
registeredGroup = settings.getProperty(HooksSettings.REGISTERED_GROUP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,8 @@ public enum AuthGroupType {
|
|||||||
/** Player does not have an account. */
|
/** Player does not have an account. */
|
||||||
UNREGISTERED,
|
UNREGISTERED,
|
||||||
|
|
||||||
/** Registered? */
|
/** Player is registered but not logged in. */
|
||||||
REGISTERED, // TODO #761: Remove this or the NOT_LOGGED_IN one
|
REGISTERED_UNAUTHENTICATED,
|
||||||
|
|
||||||
/** Player is registered and not logged in. */
|
|
||||||
NOT_LOGGED_IN,
|
|
||||||
|
|
||||||
/** Player is logged in. */
|
/** Player is logged in. */
|
||||||
LOGGED_IN
|
LOGGED_IN
|
||||||
|
@ -19,8 +19,8 @@ import org.bukkit.plugin.PluginManager;
|
|||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.ArrayList;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -255,12 +255,12 @@ public class PermissionsManager implements Reloadable {
|
|||||||
*
|
*
|
||||||
* @param player The player.
|
* @param player The player.
|
||||||
*
|
*
|
||||||
* @return Permission groups, or an empty list if this feature is not supported.
|
* @return Permission groups, or an empty collection if this feature is not supported.
|
||||||
*/
|
*/
|
||||||
public List<String> getGroups(Player player) {
|
public Collection<String> getGroups(Player player) {
|
||||||
// If no permissions system is used, return an empty list
|
// If no permissions system is used, return an empty list
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return new ArrayList<>();
|
return Collections.emptyList();
|
||||||
|
|
||||||
return handler.getGroups(player);
|
return handler.getGroups(player);
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ public class PermissionsManager implements Reloadable {
|
|||||||
* @return True if the player is in the specified group, false otherwise.
|
* @return True if the player is in the specified group, false otherwise.
|
||||||
* False is also returned if groups aren't supported by the used permissions system.
|
* False is also returned if groups aren't supported by the used permissions system.
|
||||||
*/
|
*/
|
||||||
public boolean inGroup(Player player, String groupName) {
|
public boolean isInGroup(Player player, String groupName) {
|
||||||
// If no permissions system is used, return false
|
// If no permissions system is used, return false
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return false;
|
return false;
|
||||||
@ -307,42 +307,12 @@ public class PermissionsManager implements Reloadable {
|
|||||||
* False is also returned if this feature isn't supported for the current permissions system.
|
* False is also returned if this feature isn't supported for the current permissions system.
|
||||||
*/
|
*/
|
||||||
public boolean addGroup(Player player, String groupName) {
|
public boolean addGroup(Player player, String groupName) {
|
||||||
if (StringUtils.isEmpty(groupName)) {
|
if (!isEnabled() || StringUtils.isEmpty(groupName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no permissions system is used, return false
|
|
||||||
if (!isEnabled()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handler.addToGroup(player, groupName);
|
return handler.addToGroup(player, groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the permission groups of a player, if supported.
|
|
||||||
*
|
|
||||||
* @param player The player
|
|
||||||
* @param groupNames The name of the groups to add.
|
|
||||||
*
|
|
||||||
* @return True if succeed, false otherwise.
|
|
||||||
* False is also returned if this feature isn't supported for the current permissions system.
|
|
||||||
*/
|
|
||||||
public boolean addGroups(Player player, List<String> groupNames) {
|
|
||||||
// If no permissions system is used, return false
|
|
||||||
if (!isEnabled())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Add each group to the user
|
|
||||||
boolean result = true;
|
|
||||||
for (String groupName : groupNames)
|
|
||||||
if (!addGroup(player, groupName))
|
|
||||||
result = false;
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the permission group of a player, if supported.
|
* Remove the permission group of a player, if supported.
|
||||||
*
|
*
|
||||||
@ -352,8 +322,7 @@ public class PermissionsManager implements Reloadable {
|
|||||||
* @return True if succeed, false otherwise.
|
* @return True if succeed, false otherwise.
|
||||||
* False is also returned if this feature isn't supported for the current permissions system.
|
* False is also returned if this feature isn't supported for the current permissions system.
|
||||||
*/
|
*/
|
||||||
public boolean removeGroup(Player player, String groupName) {
|
public boolean removeGroups(Player player, String groupName) {
|
||||||
// If no permissions system is used, return false
|
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -369,16 +338,18 @@ public class PermissionsManager implements Reloadable {
|
|||||||
* @return True if succeed, false otherwise.
|
* @return True if succeed, false otherwise.
|
||||||
* False is also returned if this feature isn't supported for the current permissions system.
|
* False is also returned if this feature isn't supported for the current permissions system.
|
||||||
*/
|
*/
|
||||||
public boolean removeGroups(Player player, List<String> groupNames) {
|
public boolean removeGroups(Player player, String... groupNames) {
|
||||||
// If no permissions system is used, return false
|
// If no permissions system is used, return false
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Add each group to the user
|
// Add each group to the user
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
for (String groupName : groupNames)
|
for (String groupName : groupNames) {
|
||||||
if (!removeGroup(player, groupName))
|
if (!handler.removeFromGroup(player, groupName)) {
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return the result
|
// Return the result
|
||||||
return result;
|
return result;
|
||||||
@ -402,41 +373,6 @@ public class PermissionsManager implements Reloadable {
|
|||||||
return handler.setGroup(player, groupName);
|
return handler.setGroup(player, groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the permission groups of a player, if supported.
|
|
||||||
* This clears the current groups of the player.
|
|
||||||
*
|
|
||||||
* @param player The player
|
|
||||||
* @param groupNames The name of the groups to set.
|
|
||||||
*
|
|
||||||
* @return True if succeed, false otherwise.
|
|
||||||
* False is also returned if this feature isn't supported for the current permissions system.
|
|
||||||
*/
|
|
||||||
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.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Set the main group
|
|
||||||
if (!setGroup(player, groupNames.get(0)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Add the rest of the groups
|
|
||||||
boolean result = true;
|
|
||||||
for (int i = 1; i < groupNames.size(); i++) {
|
|
||||||
// Get the group name
|
|
||||||
String groupName = groupNames.get(i);
|
|
||||||
|
|
||||||
// Add this group
|
|
||||||
if (!addGroup(player, groupName)) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all groups of the specified player, if supported.
|
* Remove all groups of the specified player, if supported.
|
||||||
* Systems like Essentials GroupManager don't allow all groups to be removed from a player, thus the user will stay
|
* Systems like Essentials GroupManager don't allow all groups to be removed from a player, thus the user will stay
|
||||||
@ -453,9 +389,9 @@ public class PermissionsManager implements Reloadable {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get a list of current groups
|
// Get a list of current groups
|
||||||
List<String> groupNames = getGroups(player);
|
Collection<String> groupNames = getGroups(player);
|
||||||
|
|
||||||
// Remove each group
|
// Remove each group
|
||||||
return removeGroups(player, groupNames);
|
return removeGroups(player, groupNames.toArray(new String[groupNames.size()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,12 @@ public enum PlayerStatePermission implements PermissionNode {
|
|||||||
/**
|
/**
|
||||||
* Permission to bypass the purging process.
|
* Permission to bypass the purging process.
|
||||||
*/
|
*/
|
||||||
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED);
|
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission to use the /authme debug command.
|
||||||
|
*/
|
||||||
|
DEBUG_COMMAND("authme.debug", DefaultPermission.OP_ONLY);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The permission node.
|
* The permission node.
|
||||||
|
@ -9,6 +9,12 @@ import org.bukkit.entity.Player;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for bPermissions.
|
||||||
|
*
|
||||||
|
* @see <a href="https://dev.bukkit.org/projects/bpermissions">bPermissions Bukkit page</a>
|
||||||
|
* @see <a href="https://github.com/rymate1234/bPermissions/">bPermissions on Github</a>
|
||||||
|
*/
|
||||||
public class BPermissionsHandler implements PermissionHandler {
|
public class BPermissionsHandler implements PermissionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,19 +55,6 @@ public class BPermissionsHandler implements PermissionHandler {
|
|||||||
return Arrays.asList(ApiLayer.getGroups(player.getWorld().getName(), CalculableType.USER, player.getName()));
|
return Arrays.asList(ApiLayer.getGroups(player.getWorld().getName(), CalculableType.USER, player.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPrimaryGroup(Player player) {
|
|
||||||
// Get the groups of the player
|
|
||||||
List<String> groups = getGroups(player);
|
|
||||||
|
|
||||||
// Make sure there is any group available, or return null
|
|
||||||
if (groups.isEmpty())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Return the first group
|
|
||||||
return groups.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionsSystemType getPermissionSystem() {
|
public PermissionsSystemType getPermissionSystem() {
|
||||||
return PermissionsSystemType.B_PERMISSIONS;
|
return PermissionsSystemType.B_PERMISSIONS;
|
||||||
|
@ -2,9 +2,10 @@ package fr.xephi.authme.permission.handlers;
|
|||||||
|
|
||||||
import fr.xephi.authme.permission.PermissionNode;
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
public interface PermissionHandler {
|
public interface PermissionHandler {
|
||||||
@ -48,7 +49,9 @@ public interface PermissionHandler {
|
|||||||
* @return True if the player is in the specified group, false otherwise.
|
* @return True if the player is in the specified group, false otherwise.
|
||||||
* False is also returned if groups aren't supported by the used permissions system.
|
* False is also returned if groups aren't supported by the used permissions system.
|
||||||
*/
|
*/
|
||||||
boolean isInGroup(Player player, String group);
|
default boolean isInGroup(Player player, String group) {
|
||||||
|
return getGroups(player).contains(group);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the permission group of a player, if supported.
|
* Remove the permission group of a player, if supported.
|
||||||
@ -80,7 +83,7 @@ public interface PermissionHandler {
|
|||||||
*
|
*
|
||||||
* @return Permission groups, or an empty list if this feature is not supported.
|
* @return Permission groups, or an empty list if this feature is not supported.
|
||||||
*/
|
*/
|
||||||
List<String> getGroups(Player player);
|
Collection<String> getGroups(Player player);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the primary group of a player, if available.
|
* Get the primary group of a player, if available.
|
||||||
@ -89,7 +92,13 @@ public interface PermissionHandler {
|
|||||||
*
|
*
|
||||||
* @return The name of the primary permission group. Or null.
|
* @return The name of the primary permission group. Or null.
|
||||||
*/
|
*/
|
||||||
String getPrimaryGroup(Player player);
|
default String getPrimaryGroup(Player player) {
|
||||||
|
Collection<String> groups = getGroups(player);
|
||||||
|
if (Utils.isCollectionEmpty(groups)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return groups.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the permission system that is being used.
|
* Get the permission system that is being used.
|
||||||
|
@ -12,6 +12,11 @@ import org.bukkit.plugin.PluginManager;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for PermissionsBukkit.
|
||||||
|
*
|
||||||
|
* @see <a href="https://dev.bukkit.org/projects/permbukkit">PermissionsBukkit Bukkit page</a>
|
||||||
|
*/
|
||||||
public class PermissionsBukkitHandler implements PermissionHandler {
|
public class PermissionsBukkitHandler implements PermissionHandler {
|
||||||
|
|
||||||
private PermissionsPlugin permissionsBukkitInstance;
|
private PermissionsPlugin permissionsBukkitInstance;
|
||||||
@ -26,7 +31,8 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addToGroup(Player player, String group) {
|
public boolean addToGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player addgroup " + player.getName() + " " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player addgroup " + player.getName() + " " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -39,46 +45,27 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInGroup(Player player, String group) {
|
|
||||||
List<String> groupNames = getGroups(player);
|
|
||||||
|
|
||||||
return groupNames.contains(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeFromGroup(Player player, String group) {
|
public boolean removeFromGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player removegroup " + player.getName() + " " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player removegroup " + player.getName() + " " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setGroup(Player player, String group) {
|
public boolean setGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player setgroup " + player.getName() + " " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player setgroup " + player.getName() + " " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(Player player) {
|
public List<String> getGroups(Player player) {
|
||||||
List<String> groups = new ArrayList<String>();
|
List<String> groups = new ArrayList<>();
|
||||||
for (Group group : permissionsBukkitInstance.getGroups(player.getUniqueId())) {
|
for (Group group : permissionsBukkitInstance.getGroups(player.getUniqueId())) {
|
||||||
groups.add(group.getName());
|
groups.add(group.getName());
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPrimaryGroup(Player player) {
|
|
||||||
// Get the groups of the player
|
|
||||||
List<String> groups = getGroups(player);
|
|
||||||
|
|
||||||
// Make sure there is any group available, or return null
|
|
||||||
if (groups.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the first group
|
|
||||||
return groups.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionsSystemType getPermissionSystem() {
|
public PermissionsSystemType getPermissionSystem() {
|
||||||
return PermissionsSystemType.PERMISSIONS_BUKKIT;
|
return PermissionsSystemType.PERMISSIONS_BUKKIT;
|
||||||
|
@ -10,6 +10,12 @@ import ru.tehkode.permissions.bukkit.PermissionsEx;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for PermissionsEx.
|
||||||
|
*
|
||||||
|
* @see <a href="https://dev.bukkit.org/projects/permissionsex">PermissionsEx Bukkit page</a>
|
||||||
|
* @see <a href="https://github.com/PEXPlugins/PermissionsEx">PermissionsEx on Github</a>
|
||||||
|
*/
|
||||||
public class PermissionsExHandler implements PermissionHandler {
|
public class PermissionsExHandler implements PermissionHandler {
|
||||||
|
|
||||||
private PermissionManager permissionManager;
|
private PermissionManager permissionManager;
|
||||||
@ -72,17 +78,6 @@ public class PermissionsExHandler implements PermissionHandler {
|
|||||||
return user.getParentIdentifiers(null);
|
return user.getParentIdentifiers(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPrimaryGroup(Player player) {
|
|
||||||
PermissionUser user = permissionManager.getUser(player);
|
|
||||||
|
|
||||||
List<String> groups = user.getParentIdentifiers(null);
|
|
||||||
if (groups.isEmpty())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return groups.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionsSystemType getPermissionSystem() {
|
public PermissionsSystemType getPermissionSystem() {
|
||||||
return PermissionsSystemType.PERMISSIONS_EX;
|
return PermissionsSystemType.PERMISSIONS_EX;
|
||||||
|
@ -10,6 +10,12 @@ import org.bukkit.plugin.RegisteredServiceProvider;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for permissions via Vault.
|
||||||
|
*
|
||||||
|
* @see <a href="https://dev.bukkit.org/projects/vault">Vault Bukkit page</a>
|
||||||
|
* @see <a href="https://github.com/milkbowl/Vault">Vault on Github</a>
|
||||||
|
*/
|
||||||
public class VaultHandler implements PermissionHandler {
|
public class VaultHandler implements PermissionHandler {
|
||||||
|
|
||||||
private Permission vaultProvider;
|
private Permission vaultProvider;
|
||||||
|
@ -6,10 +6,15 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
|
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for zPermissions.
|
||||||
|
*
|
||||||
|
* @see <a href="https://dev.bukkit.org/projects/zpermissions">zPermissions Bukkit page</a>
|
||||||
|
* @see <a href="https://github.com/ZerothAngel/zPermissions">zPermissions on Github</a>
|
||||||
|
*/
|
||||||
public class ZPermissionsHandler implements PermissionHandler {
|
public class ZPermissionsHandler implements PermissionHandler {
|
||||||
|
|
||||||
private ZPermissionsService zPermissionsService;
|
private ZPermissionsService zPermissionsService;
|
||||||
@ -25,7 +30,8 @@ public class ZPermissionsHandler implements PermissionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addToGroup(Player player, String group) {
|
public boolean addToGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player " + player.getName() + " addgroup " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player " + player.getName() + " addgroup " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -36,31 +42,29 @@ public class ZPermissionsHandler implements PermissionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
Map<String, Boolean> perms = zPermissionsService.getPlayerPermissions(null, null, name);
|
Map<String, Boolean> perms = zPermissionsService.getPlayerPermissions(null, null, name);
|
||||||
if (perms.containsKey(node.getNode()))
|
if (perms.containsKey(node.getNode())) {
|
||||||
return perms.get(node.getNode());
|
return perms.get(node.getNode());
|
||||||
else
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInGroup(Player player, String group) {
|
|
||||||
return getGroups(player).contains(group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeFromGroup(Player player, String group) {
|
public boolean removeFromGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player " + player.getName() + " removegroup " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player " + player.getName() + " removegroup " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setGroup(Player player, String group) {
|
public boolean setGroup(Player player, String group) {
|
||||||
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "permissions player " + player.getName() + " setgroup " + group);
|
return Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||||
|
"permissions player " + player.getName() + " setgroup " + group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(Player player) {
|
public Collection<String> getGroups(Player player) {
|
||||||
// TODO Gnat008 20160631: Use UUID not name?
|
// TODO Gnat008 20160631: Use UUID not name?
|
||||||
return new ArrayList<String>(zPermissionsService.getPlayerGroups(player.getName()));
|
return zPermissionsService.getPlayerGroups(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.process.join;
|
package fr.xephi.authme.process.join;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.SessionManager;
|
import fr.xephi.authme.data.SessionManager;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
@ -8,30 +7,32 @@ import fr.xephi.authme.data.auth.PlayerCache;
|
|||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.events.ProtectInventoryEvent;
|
import fr.xephi.authme.events.ProtectInventoryEvent;
|
||||||
import fr.xephi.authme.service.PluginHookService;
|
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
import fr.xephi.authme.process.AsynchronousProcess;
|
import fr.xephi.authme.process.AsynchronousProcess;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.login.AsynchronousLogin;
|
import fr.xephi.authme.process.login.AsynchronousLogin;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import fr.xephi.authme.service.PluginHookService;
|
||||||
|
import fr.xephi.authme.service.ValidationService;
|
||||||
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Server;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
|
|
||||||
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
|
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
|
||||||
|
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronous process for when a player joins.
|
* Asynchronous process for when a player joins.
|
||||||
@ -39,7 +40,7 @@ import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
|
|||||||
public class AsynchronousJoin implements AsynchronousProcess {
|
public class AsynchronousJoin implements AsynchronousProcess {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AuthMe plugin;
|
private Server server;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource database;
|
private DataSource database;
|
||||||
@ -71,6 +72,9 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
@Inject
|
@Inject
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
|
||||||
AsynchronousJoin() {
|
AsynchronousJoin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +95,13 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
pluginHookService.setEssentialsSocialSpyStatus(player, false);
|
pluginHookService.setEssentialsSocialSpyStatus(player, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNameRestricted(name, ip, player.getAddress().getHostName())) {
|
if (!validationService.fulfillsNameRestrictions(player)) {
|
||||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
player.kickPlayer(service.retrieveSingleMessage(MessageKey.NOT_OWNER_ERROR));
|
player.kickPlayer(service.retrieveSingleMessage(MessageKey.NOT_OWNER_ERROR));
|
||||||
if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) {
|
if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) {
|
||||||
plugin.getServer().banIP(ip);
|
server.banIP(ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -112,7 +116,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
|
|
||||||
if (isAuthAvailable) {
|
if (isAuthAvailable) {
|
||||||
limboCache.addPlayerData(player);
|
limboCache.addPlayerData(player);
|
||||||
service.setGroup(player, AuthGroupType.NOT_LOGGED_IN);
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
|
|
||||||
// Protect inventory
|
// Protect inventory
|
||||||
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||||
@ -130,14 +134,16 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
PlayerAuth auth = database.getAuth(name);
|
PlayerAuth auth = database.getAuth(name);
|
||||||
database.setUnlogged(name);
|
database.setUnlogged(name);
|
||||||
playerCache.removePlayer(name);
|
playerCache.removePlayer(name);
|
||||||
if (auth != null && auth.getIp().equals(ip)) {
|
if (auth != null) {
|
||||||
|
if (auth.getIp().equals(ip)) {
|
||||||
service.send(player, MessageKey.SESSION_RECONNECTION);
|
service.send(player, MessageKey.SESSION_RECONNECTION);
|
||||||
bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player));
|
bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player));
|
||||||
return;
|
return;
|
||||||
} else if (service.getProperty(PluginSettings.SESSIONS_EXPIRE_ON_IP_CHANGE)) {
|
} else {
|
||||||
service.send(player, MessageKey.SESSION_EXPIRED);
|
service.send(player, MessageKey.SESSION_EXPIRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not Registered. Delete old data, load default one.
|
// Not Registered. Delete old data, load default one.
|
||||||
limboCache.deletePlayerData(player);
|
limboCache.deletePlayerData(player);
|
||||||
@ -178,36 +184,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
limboPlayerTaskManager.registerMessageTask(name, isAuthAvailable);
|
limboPlayerTaskManager.registerMessageTask(name, isAuthAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the name is restricted based on the restriction settings.
|
|
||||||
*
|
|
||||||
* @param name The name to check
|
|
||||||
* @param ip The IP address of the player
|
|
||||||
* @param domain The hostname of the IP address
|
|
||||||
*
|
|
||||||
* @return True if the name is restricted (IP/domain is not allowed for the given name),
|
|
||||||
* false if the restrictions are met or if the name has no restrictions to it
|
|
||||||
*/
|
|
||||||
private boolean isNameRestricted(String name, String ip, String domain) {
|
|
||||||
if (!service.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean nameFound = false;
|
|
||||||
for (String entry : service.getProperty(RestrictionSettings.ALLOWED_RESTRICTED_USERS)) {
|
|
||||||
String[] args = entry.split(";");
|
|
||||||
String testName = args[0];
|
|
||||||
String testIp = args[1];
|
|
||||||
if (testName.equalsIgnoreCase(name)) {
|
|
||||||
nameFound = true;
|
|
||||||
if ((ip != null && testIp.equals(ip)) || (domain != null && testIp.equalsIgnoreCase(domain))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nameFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the maximum number of accounts has been exceeded for the given IP address (according to
|
* Checks whether the maximum number of accounts has been exceeded for the given IP address (according to
|
||||||
* settings and permissions). If this is the case, the player is kicked.
|
* settings and permissions). If this is the case, the player is kicked.
|
||||||
|
@ -12,7 +12,6 @@ import fr.xephi.authme.datasource.DataSource;
|
|||||||
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
|
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AdminPermission;
|
import fr.xephi.authme.permission.AdminPermission;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.permission.PlayerPermission;
|
import fr.xephi.authme.permission.PlayerPermission;
|
||||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
import fr.xephi.authme.process.AsynchronousProcess;
|
import fr.xephi.authme.process.AsynchronousProcess;
|
||||||
@ -46,9 +45,6 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
@Inject
|
@Inject
|
||||||
private CommonService service;
|
private CommonService service;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PermissionsManager permissionsManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@ -269,8 +265,8 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bukkitService.dispatchConsoleCommand(command
|
bukkitService.dispatchConsoleCommand(command
|
||||||
.replaceAll("%playername%", player.getName())
|
.replace("%playername%", player.getName())
|
||||||
.replaceAll("%playerip%", ip)
|
.replace("%playerip%", ip)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,10 +296,10 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
|
|
||||||
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
|
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
|
||||||
if (onlinePlayer.getName().equalsIgnoreCase(player.getName())
|
if (onlinePlayer.getName().equalsIgnoreCase(player.getName())
|
||||||
&& permissionsManager.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) {
|
&& service.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) {
|
||||||
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_SELF, Integer.toString(auths.size()));
|
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_SELF, Integer.toString(auths.size()));
|
||||||
onlinePlayer.sendMessage(message);
|
onlinePlayer.sendMessage(message);
|
||||||
} else if (permissionsManager.hasPermission(onlinePlayer, AdminPermission.SEE_OTHER_ACCOUNTS)) {
|
} else if (service.hasPermission(onlinePlayer, AdminPermission.SEE_OTHER_ACCOUNTS)) {
|
||||||
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_OTHER,
|
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_OTHER,
|
||||||
player.getName(), Integer.toString(auths.size()));
|
player.getName(), Integer.toString(auths.size()));
|
||||||
onlinePlayer.sendMessage(message);
|
onlinePlayer.sendMessage(message);
|
||||||
@ -323,7 +319,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
boolean hasReachedMaxLoggedInPlayersForIp(Player player, String ip) {
|
boolean hasReachedMaxLoggedInPlayersForIp(Player player, String ip) {
|
||||||
// Do not perform the check if player has multiple accounts permission or if IP is localhost
|
// Do not perform the check if player has multiple accounts permission or if IP is localhost
|
||||||
if (service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP) <= 0
|
if (service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP) <= 0
|
||||||
|| permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|
|| service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|
||||||
|| "127.0.0.1".equalsIgnoreCase(ip)
|
|| "127.0.0.1".equalsIgnoreCase(ip)
|
||||||
|| "localhost".equalsIgnoreCase(ip)) {
|
|| "localhost".equalsIgnoreCase(ip)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.process.login;
|
package fr.xephi.authme.process.login;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
@ -8,28 +7,26 @@ import fr.xephi.authme.datasource.DataSource;
|
|||||||
import fr.xephi.authme.events.LoginEvent;
|
import fr.xephi.authme.events.LoginEvent;
|
||||||
import fr.xephi.authme.events.RestoreInventoryEvent;
|
import fr.xephi.authme.events.RestoreInventoryEvent;
|
||||||
import fr.xephi.authme.listener.PlayerListener;
|
import fr.xephi.authme.listener.PlayerListener;
|
||||||
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.BungeeService;
|
import fr.xephi.authme.service.BungeeService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.service.TeleportationService;
|
import fr.xephi.authme.service.TeleportationService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.WelcomeMessageConfiguration;
|
||||||
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.PluginManager;
|
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
|
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
|
||||||
|
|
||||||
public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthMe plugin;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BungeeService bungeeService;
|
private BungeeService bungeeService;
|
||||||
|
|
||||||
@ -39,9 +36,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
@Inject
|
@Inject
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PluginManager pluginManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private TeleportationService teleportationService;
|
private TeleportationService teleportationService;
|
||||||
|
|
||||||
@ -52,14 +46,17 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Settings settings;
|
private CommonService commonService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private WelcomeMessageConfiguration welcomeMessageConfiguration;
|
||||||
|
|
||||||
ProcessSyncPlayerLogin() {
|
ProcessSyncPlayerLogin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreInventory(Player player) {
|
private void restoreInventory(Player player) {
|
||||||
RestoreInventoryEvent event = new RestoreInventoryEvent(player);
|
RestoreInventoryEvent event = new RestoreInventoryEvent(player);
|
||||||
pluginManager.callEvent(event);
|
bukkitService.callEvent(event);
|
||||||
if (!event.isCancelled()) {
|
if (!event.isCancelled()) {
|
||||||
player.updateInventory();
|
player.updateInventory();
|
||||||
}
|
}
|
||||||
@ -76,8 +73,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
// do we really need to use location from database for now?
|
// do we really need to use location from database for now?
|
||||||
// because LimboCache#restoreData teleport player to last location.
|
// because LimboCache#restoreData teleport player to last location.
|
||||||
}
|
}
|
||||||
|
commonService.setGroup(player, AuthGroupType.LOGGED_IN);
|
||||||
|
|
||||||
if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||||
restoreInventory(player);
|
restoreInventory(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +92,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
if (commonService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||||
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,15 +101,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
player.saveData();
|
player.saveData();
|
||||||
|
|
||||||
// Login is done, display welcome message
|
// Login is done, display welcome message
|
||||||
if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
|
List<String> welcomeMessage = welcomeMessageConfiguration.getWelcomeMessage(player);
|
||||||
if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
|
if (commonService.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
|
||||||
for (String s : settings.getWelcomeMessage()) {
|
if (commonService.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
|
||||||
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
|
welcomeMessage.forEach(bukkitService::broadcastMessage);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (String s : settings.getWelcomeMessage()) {
|
welcomeMessage.forEach(player::sendMessage);
|
||||||
player.sendMessage(plugin.replaceAllInfo(s, player));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set player's data to unauthenticated
|
// Set player's data to unauthenticated
|
||||||
service.setGroup(player, AuthGroupType.NOT_LOGGED_IN);
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
player.setOp(false);
|
player.setOp(false);
|
||||||
player.setAllowFlight(false);
|
player.setAllowFlight(false);
|
||||||
// Remove speed
|
// Remove speed
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package fr.xephi.authme.process.quit;
|
package fr.xephi.authme.process.quit;
|
||||||
|
|
||||||
import fr.xephi.authme.data.backup.LimboPlayerStorage;
|
import fr.xephi.authme.data.limbo.LimboPlayerStorage;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
@ -3,9 +3,8 @@ package fr.xephi.authme.process.register;
|
|||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -25,12 +24,10 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void processEmailRegister(Player player) {
|
public void processEmailRegister(Player player) {
|
||||||
final String name = player.getName().toLowerCase();
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
if (!service.getProperty(HooksSettings.REGISTERED_GROUP).isEmpty()) {
|
|
||||||
service.setGroup(player, AuthGroupType.REGISTERED);
|
|
||||||
}
|
|
||||||
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
|
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
|
||||||
|
|
||||||
|
final String name = player.getName().toLowerCase();
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
limboPlayerTaskManager.registerTimeoutTask(player);
|
||||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
limboPlayerTaskManager.registerMessageTask(name, true);
|
||||||
|
|
||||||
|
@ -4,12 +4,11 @@ import fr.xephi.authme.ConsoleLogger;
|
|||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboCache;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
import fr.xephi.authme.service.BungeeService;
|
import fr.xephi.authme.service.BungeeService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
@ -56,10 +55,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void processPasswordRegister(Player player) {
|
public void processPasswordRegister(Player player) {
|
||||||
if (!service.getProperty(HooksSettings.REGISTERED_GROUP).isEmpty()) {
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
service.setGroup(player, AuthGroupType.REGISTERED);
|
|
||||||
}
|
|
||||||
|
|
||||||
service.send(player, MessageKey.REGISTER_SUCCESS);
|
service.send(player, MessageKey.REGISTER_SUCCESS);
|
||||||
|
|
||||||
if (!service.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
|
if (!service.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
|
||||||
|
@ -2,7 +2,7 @@ package fr.xephi.authme.process.register.executors;
|
|||||||
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.mail.SendMailSSL;
|
import fr.xephi.authme.mail.EmailService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.process.SyncProcessManager;
|
import fr.xephi.authme.process.SyncProcessManager;
|
||||||
@ -15,8 +15,8 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
|
||||||
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
|
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
|
||||||
|
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
||||||
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
|
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +34,7 @@ class EmailRegisterExecutorProvider {
|
|||||||
private CommonService commonService;
|
private CommonService commonService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SendMailSSL sendMailSsl;
|
private EmailService emailService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SyncProcessManager syncProcessManager;
|
private SyncProcessManager syncProcessManager;
|
||||||
@ -80,7 +80,7 @@ class EmailRegisterExecutorProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executePostPersistAction() {
|
public void executePostPersistAction() {
|
||||||
boolean couldSendMail = sendMailSsl.sendPasswordMail(player.getName(), email, password);
|
boolean couldSendMail = emailService.sendPasswordMail(player.getName(), email, password);
|
||||||
if (couldSendMail) {
|
if (couldSendMail) {
|
||||||
syncProcessManager.processSyncEmailRegister(player);
|
syncProcessManager.processSyncEmailRegister(player);
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,10 +56,10 @@ class PasswordRegisterExecutorProvider {
|
|||||||
/** Registration executor for password registration. */
|
/** Registration executor for password registration. */
|
||||||
class PasswordRegisterExecutor implements RegistrationExecutor {
|
class PasswordRegisterExecutor implements RegistrationExecutor {
|
||||||
|
|
||||||
protected final Player player;
|
private final Player player;
|
||||||
private final String password;
|
private final String password;
|
||||||
private final String email;
|
private final String email;
|
||||||
protected HashedPassword hashedPassword;
|
private HashedPassword hashedPassword;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -105,6 +105,14 @@ class PasswordRegisterExecutorProvider {
|
|||||||
}
|
}
|
||||||
syncProcessManager.processSyncPasswordRegister(player);
|
syncProcessManager.processSyncPasswordRegister(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HashedPassword getHashedPassword() {
|
||||||
|
return hashedPassword;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Executor for password registration via API call. */
|
/** Executor for password registration via API call. */
|
||||||
@ -147,8 +155,9 @@ class PasswordRegisterExecutorProvider {
|
|||||||
public void executePostPersistAction() {
|
public void executePostPersistAction() {
|
||||||
super.executePostPersistAction();
|
super.executePostPersistAction();
|
||||||
|
|
||||||
String qrCodeUrl = TwoFactor.getQRBarcodeURL(player.getName(), Bukkit.getIp(), hashedPassword.getHash());
|
String hash = getHashedPassword().getHash();
|
||||||
commonService.send(player, MessageKey.TWO_FACTOR_CREATE, hashedPassword.getHash(), qrCodeUrl);
|
String qrCodeUrl = TwoFactor.getQRBarcodeURL(getPlayer().getName(), Bukkit.getIp(), hash);
|
||||||
|
commonService.send(getPlayer(), MessageKey.TWO_FACTOR_CREATE, hash, qrCodeUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package fr.xephi.authme.security;
|
package fr.xephi.authme.security;
|
||||||
|
|
||||||
import ch.jalu.injector.Injector;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.events.PasswordEncryptionEvent;
|
import fr.xephi.authme.events.PasswordEncryptionEvent;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.initialization.factory.Factory;
|
||||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
@ -29,7 +29,7 @@ public class PasswordSecurity implements Reloadable {
|
|||||||
private PluginManager pluginManager;
|
private PluginManager pluginManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Injector injector;
|
private Factory<EncryptionMethod> hashAlgorithmFactory;
|
||||||
|
|
||||||
private HashAlgorithm algorithm;
|
private HashAlgorithm algorithm;
|
||||||
private Collection<HashAlgorithm> legacyAlgorithms;
|
private Collection<HashAlgorithm> legacyAlgorithms;
|
||||||
@ -154,7 +154,7 @@ public class PasswordSecurity implements Reloadable {
|
|||||||
if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) {
|
if (HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return injector.newInstance(algorithm.getClazz());
|
return hashAlgorithmFactory.newInstance(algorithm.getClazz());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hashPasswordForNewAlgorithm(String password, String playerName) {
|
private void hashPasswordForNewAlgorithm(String password, String playerName) {
|
||||||
|
@ -8,15 +8,15 @@ public abstract class SeparateSaltMethod implements EncryptionMethod {
|
|||||||
@Override
|
@Override
|
||||||
public abstract String computeHash(String password, String salt, String name);
|
public abstract String computeHash(String password, String salt, String name);
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract String generateSalt();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HashedPassword computeHash(String password, String name) {
|
public HashedPassword computeHash(String password, String name) {
|
||||||
String salt = generateSalt();
|
String salt = generateSalt();
|
||||||
return new HashedPassword(computeHash(password, salt, name), salt);
|
return new HashedPassword(computeHash(password, salt, name), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract String generateSalt();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
|
public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
|
||||||
return hashedPassword.getHash().equals(computeHash(password, hashedPassword.getSalt(), null));
|
return hashedPassword.getHash().equals(computeHash(password, hashedPassword.getSalt(), null));
|
||||||
|
@ -17,13 +17,13 @@ public abstract class UsernameSaltMethod implements EncryptionMethod {
|
|||||||
public abstract HashedPassword computeHash(String password, String name);
|
public abstract HashedPassword computeHash(String password, String name);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
return hashedPassword.getHash().equals(computeHash(password, name).getHash());
|
return computeHash(password, name).getHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public boolean comparePassword(String password, HashedPassword hashedPassword, String name) {
|
||||||
return computeHash(password, name).getHash();
|
return hashedPassword.getHash().equals(computeHash(password, name).getHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,7 +30,6 @@ public class AntiBotService implements SettingsDependent {
|
|||||||
// Settings
|
// Settings
|
||||||
private int duration;
|
private int duration;
|
||||||
private int sensibility;
|
private int sensibility;
|
||||||
private int delay;
|
|
||||||
private int interval;
|
private int interval;
|
||||||
// Service status
|
// Service status
|
||||||
private AntiBotStatus antiBotStatus;
|
private AntiBotStatus antiBotStatus;
|
||||||
@ -60,7 +59,6 @@ public class AntiBotService implements SettingsDependent {
|
|||||||
// Load settings
|
// Load settings
|
||||||
duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION);
|
duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION);
|
||||||
sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY);
|
sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY);
|
||||||
delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY);
|
|
||||||
interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL);
|
interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL);
|
||||||
|
|
||||||
// Stop existing protection
|
// Stop existing protection
|
||||||
@ -77,6 +75,7 @@ public class AntiBotService implements SettingsDependent {
|
|||||||
|
|
||||||
// Delay the schedule on first start
|
// Delay the schedule on first start
|
||||||
if (startup) {
|
if (startup) {
|
||||||
|
int delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY);
|
||||||
bukkitService.scheduleSyncDelayedTask(enableTask, delay * TICKS_PER_SECOND);
|
bukkitService.scheduleSyncDelayedTask(enableTask, delay * TICKS_PER_SECOND);
|
||||||
startup = false;
|
startup = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,6 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
@ -172,7 +171,7 @@ public class BukkitService implements SettingsDependent {
|
|||||||
* @return a BukkitTask that contains the id number
|
* @return a BukkitTask that contains the id number
|
||||||
* @throws IllegalArgumentException if plugin is null
|
* @throws IllegalArgumentException if plugin is null
|
||||||
* @throws IllegalStateException if this was already scheduled
|
* @throws IllegalStateException if this was already scheduled
|
||||||
* @see BukkitScheduler#runTaskTimer(Plugin, Runnable, long, long)
|
* @see BukkitScheduler#runTaskTimer(org.bukkit.plugin.Plugin, Runnable, long, long)
|
||||||
*/
|
*/
|
||||||
public BukkitTask runTaskTimer(BukkitRunnable task, long delay, long period) {
|
public BukkitTask runTaskTimer(BukkitRunnable task, long delay, long period) {
|
||||||
return task.runTaskTimer(authMe, delay, period);
|
return task.runTaskTimer(authMe, delay, period);
|
||||||
|
@ -65,16 +65,6 @@ public class CommonService {
|
|||||||
messages.send(sender, key, replacements);
|
messages.send(sender, key, replacements);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a message.
|
|
||||||
*
|
|
||||||
* @param key the key of the message
|
|
||||||
* @return the message, split by line
|
|
||||||
*/
|
|
||||||
public String[] retrieveMessage(MessageKey key) {
|
|
||||||
return messages.retrieve(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a message in one piece.
|
* Retrieves a message in one piece.
|
||||||
*
|
*
|
||||||
@ -101,10 +91,10 @@ public class CommonService {
|
|||||||
*
|
*
|
||||||
* @param player the player to process
|
* @param player the player to process
|
||||||
* @param group the group to add the player to
|
* @param group the group to add the player to
|
||||||
* @return true on success, false otherwise
|
|
||||||
*/
|
*/
|
||||||
public boolean setGroup(Player player, AuthGroupType group) {
|
// TODO ljacqu 20170304: Move this out of CommonService
|
||||||
return authGroupHandler.setGroup(player, group);
|
public void setGroup(Player player, AuthGroupType group) {
|
||||||
|
authGroupHandler.setGroup(player, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
package fr.xephi.authme.service;
|
package fr.xephi.authme.service;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import fr.xephi.authme.initialization.HasCleanup;
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.util.RandomStringUtils;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
|
import fr.xephi.authme.util.RandomStringUtils;
|
||||||
|
import fr.xephi.authme.util.expiring.ExpiringMap;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Map;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.SecuritySettings.RECOVERY_CODE_HOURS_VALID;
|
import static fr.xephi.authme.settings.properties.SecuritySettings.RECOVERY_CODE_HOURS_VALID;
|
||||||
import static fr.xephi.authme.util.Utils.MILLIS_PER_HOUR;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager for recovery codes.
|
* Manager for recovery codes.
|
||||||
*/
|
*/
|
||||||
public class RecoveryCodeService implements SettingsDependent {
|
public class RecoveryCodeService implements SettingsDependent, HasCleanup {
|
||||||
|
|
||||||
private Map<String, ExpiringEntry> recoveryCodes = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
|
private final ExpiringMap<String, String> recoveryCodes;
|
||||||
private int recoveryCodeLength;
|
private int recoveryCodeLength;
|
||||||
private long recoveryCodeExpirationMillis;
|
private int recoveryCodeExpiration;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RecoveryCodeService(Settings settings) {
|
RecoveryCodeService(Settings settings) {
|
||||||
reload(settings);
|
recoveryCodeLength = settings.getProperty(SecuritySettings.RECOVERY_CODE_LENGTH);
|
||||||
|
recoveryCodeExpiration = settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID);
|
||||||
|
recoveryCodes = new ExpiringMap<>(recoveryCodeExpiration, TimeUnit.HOURS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether recovery codes are enabled or not
|
* @return whether recovery codes are enabled or not
|
||||||
*/
|
*/
|
||||||
public boolean isRecoveryCodeNeeded() {
|
public boolean isRecoveryCodeNeeded() {
|
||||||
return recoveryCodeLength > 0 && recoveryCodeExpirationMillis > 0;
|
return recoveryCodeLength > 0 && recoveryCodeExpiration > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +43,7 @@ public class RecoveryCodeService implements SettingsDependent {
|
|||||||
*/
|
*/
|
||||||
public String generateCode(String player) {
|
public String generateCode(String player) {
|
||||||
String code = RandomStringUtils.generateHex(recoveryCodeLength);
|
String code = RandomStringUtils.generateHex(recoveryCodeLength);
|
||||||
recoveryCodes.put(player, new ExpiringEntry(code, System.currentTimeMillis() + recoveryCodeExpirationMillis));
|
recoveryCodes.put(player, code);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +55,8 @@ public class RecoveryCodeService implements SettingsDependent {
|
|||||||
* @return true if the code matches and has not expired, false otherwise
|
* @return true if the code matches and has not expired, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isCodeValid(String player, String code) {
|
public boolean isCodeValid(String player, String code) {
|
||||||
ExpiringEntry entry = recoveryCodes.get(player);
|
String storedCode = recoveryCodes.get(player);
|
||||||
if (entry != null) {
|
return storedCode != null && storedCode.equals(code);
|
||||||
return code != null && code.equals(entry.getCode());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,26 +71,12 @@ public class RecoveryCodeService implements SettingsDependent {
|
|||||||
@Override
|
@Override
|
||||||
public void reload(Settings settings) {
|
public void reload(Settings settings) {
|
||||||
recoveryCodeLength = settings.getProperty(SecuritySettings.RECOVERY_CODE_LENGTH);
|
recoveryCodeLength = settings.getProperty(SecuritySettings.RECOVERY_CODE_LENGTH);
|
||||||
recoveryCodeExpirationMillis = settings.getProperty(RECOVERY_CODE_HOURS_VALID) * MILLIS_PER_HOUR;
|
recoveryCodeExpiration = settings.getProperty(RECOVERY_CODE_HOURS_VALID);
|
||||||
|
recoveryCodes.setExpiration(recoveryCodeExpiration, TimeUnit.HOURS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Entry with an expiration.
|
public void performCleanup() {
|
||||||
*/
|
recoveryCodes.removeExpiredEntries();
|
||||||
@VisibleForTesting
|
|
||||||
static final class ExpiringEntry {
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final long expiration;
|
|
||||||
|
|
||||||
ExpiringEntry(String code, long expiration) {
|
|
||||||
this.code = code;
|
|
||||||
this.expiration = expiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getCode() {
|
|
||||||
return System.currentTimeMillis() < expiration ? code : null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package fr.xephi.authme.service;
|
package fr.xephi.authme.service;
|
||||||
|
|
||||||
import ch.jalu.configme.properties.Property;
|
import ch.jalu.configme.properties.Property;
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
@ -11,9 +14,10 @@ import fr.xephi.authme.settings.properties.EmailSettings;
|
|||||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -23,6 +27,8 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.util.StringUtils.isInsideString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validation service.
|
* Validation service.
|
||||||
*/
|
*/
|
||||||
@ -39,6 +45,7 @@ public class ValidationService implements Reloadable {
|
|||||||
|
|
||||||
private Pattern passwordRegex;
|
private Pattern passwordRegex;
|
||||||
private Set<String> unrestrictedNames;
|
private Set<String> unrestrictedNames;
|
||||||
|
private Multimap<String, String> restrictedNames;
|
||||||
|
|
||||||
ValidationService() {
|
ValidationService() {
|
||||||
}
|
}
|
||||||
@ -49,6 +56,9 @@ public class ValidationService implements Reloadable {
|
|||||||
passwordRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX));
|
passwordRegex = Utils.safePatternCompile(settings.getProperty(RestrictionSettings.ALLOWED_PASSWORD_REGEX));
|
||||||
// Use Set for more efficient contains() lookup
|
// Use Set for more efficient contains() lookup
|
||||||
unrestrictedNames = new HashSet<>(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES));
|
unrestrictedNames = new HashSet<>(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES));
|
||||||
|
restrictedNames = settings.getProperty(RestrictionSettings.ENABLE_RESTRICTED_USERS)
|
||||||
|
? loadNameRestrictions(settings.getProperty(RestrictionSettings.RESTRICTED_USERS))
|
||||||
|
: HashMultimap.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,9 +126,10 @@ public class ValidationService implements Reloadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String countryCode = geoIpService.getCountryCode(hostAddress);
|
String countryCode = geoIpService.getCountryCode(hostAddress);
|
||||||
return validateWhitelistAndBlacklist(countryCode,
|
boolean isCountryAllowed = validateWhitelistAndBlacklist(countryCode,
|
||||||
ProtectionSettings.COUNTRIES_WHITELIST,
|
ProtectionSettings.COUNTRIES_WHITELIST, ProtectionSettings.COUNTRIES_BLACKLIST);
|
||||||
ProtectionSettings.COUNTRIES_BLACKLIST);
|
ConsoleLogger.debug("Country code `{0}` for `{1}` is allowed: {2}", countryCode, hostAddress, isCountryAllowed);
|
||||||
|
return isCountryAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,6 +142,24 @@ public class ValidationService implements Reloadable {
|
|||||||
return unrestrictedNames.contains(name.toLowerCase());
|
return unrestrictedNames.contains(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the player meets any name restriction if present (IP/domain-based).
|
||||||
|
*
|
||||||
|
* @param player the player to check
|
||||||
|
* @return true if the player may join, false if the player does not satisfy the name restrictions
|
||||||
|
*/
|
||||||
|
public boolean fulfillsNameRestrictions(Player player) {
|
||||||
|
Collection<String> restrictions = restrictedNames.get(player.getName().toLowerCase());
|
||||||
|
if (Utils.isCollectionEmpty(restrictions)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip = PlayerUtils.getPlayerIp(player);
|
||||||
|
String domain = player.getAddress().getHostName();
|
||||||
|
return restrictions.stream()
|
||||||
|
.anyMatch(restriction -> ip.equals(restriction) || domain.equalsIgnoreCase(restriction));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies whether the given value is allowed according to the given whitelist and blacklist settings.
|
* Verifies whether the given value is allowed according to the given whitelist and blacklist settings.
|
||||||
* Whitelist has precedence over blacklist: if a whitelist is set, the value is rejected if not present
|
* Whitelist has precedence over blacklist: if a whitelist is set, the value is rejected if not present
|
||||||
@ -144,11 +173,11 @@ public class ValidationService implements Reloadable {
|
|||||||
private boolean validateWhitelistAndBlacklist(String value, Property<List<String>> whitelist,
|
private boolean validateWhitelistAndBlacklist(String value, Property<List<String>> whitelist,
|
||||||
Property<List<String>> blacklist) {
|
Property<List<String>> blacklist) {
|
||||||
List<String> whitelistValue = settings.getProperty(whitelist);
|
List<String> whitelistValue = settings.getProperty(whitelist);
|
||||||
if (!CollectionUtils.isEmpty(whitelistValue)) {
|
if (!Utils.isCollectionEmpty(whitelistValue)) {
|
||||||
return containsIgnoreCase(whitelistValue, value);
|
return containsIgnoreCase(whitelistValue, value);
|
||||||
}
|
}
|
||||||
List<String> blacklistValue = settings.getProperty(blacklist);
|
List<String> blacklistValue = settings.getProperty(blacklist);
|
||||||
return CollectionUtils.isEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value);
|
return Utils.isCollectionEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean containsIgnoreCase(Collection<String> coll, String needle) {
|
private static boolean containsIgnoreCase(Collection<String> coll, String needle) {
|
||||||
@ -160,6 +189,26 @@ public class ValidationService implements Reloadable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the configured name restrictions into a Multimap by player name (all-lowercase).
|
||||||
|
*
|
||||||
|
* @param configuredRestrictions the restriction rules to convert to a map
|
||||||
|
* @return map of allowed IPs/domain names by player name
|
||||||
|
*/
|
||||||
|
private Multimap<String, String> loadNameRestrictions(List<String> configuredRestrictions) {
|
||||||
|
Multimap<String, String> restrictions = HashMultimap.create();
|
||||||
|
for (String restriction : configuredRestrictions) {
|
||||||
|
if (isInsideString(';', restriction)) {
|
||||||
|
String[] data = restriction.split(";");
|
||||||
|
restrictions.put(data[0].toLowerCase(), data[1]);
|
||||||
|
} else {
|
||||||
|
ConsoleLogger.warning("Restricted user rule must have a ';' separating name from restriction,"
|
||||||
|
+ " but found: '" + restriction + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return restrictions;
|
||||||
|
}
|
||||||
|
|
||||||
public static final class ValidationResult {
|
public static final class ValidationResult {
|
||||||
private final MessageKey messageKey;
|
private final MessageKey messageKey;
|
||||||
private final String[] args;
|
private final String[] args;
|
||||||
@ -195,6 +244,7 @@ public class ValidationService implements Reloadable {
|
|||||||
public MessageKey getMessageKey() {
|
public MessageKey getMessageKey() {
|
||||||
return messageKey;
|
return messageKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getArgs() {
|
public String[] getArgs() {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
|
|||||||
public class Settings extends SettingsManager {
|
public class Settings extends SettingsManager {
|
||||||
|
|
||||||
private final File pluginFolder;
|
private final File pluginFolder;
|
||||||
private String[] welcomeMessage;
|
|
||||||
private String passwordEmailMessage;
|
private String passwordEmailMessage;
|
||||||
private String recoveryCodeEmailMessage;
|
private String recoveryCodeEmailMessage;
|
||||||
|
|
||||||
@ -56,19 +55,9 @@ public class Settings extends SettingsManager {
|
|||||||
return recoveryCodeEmailMessage;
|
return recoveryCodeEmailMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the lines to output after an in-game registration.
|
|
||||||
*
|
|
||||||
* @return The welcome message
|
|
||||||
*/
|
|
||||||
public String[] getWelcomeMessage() {
|
|
||||||
return welcomeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadSettingsFromFiles() {
|
private void loadSettingsFromFiles() {
|
||||||
passwordEmailMessage = readFile("email.html");
|
passwordEmailMessage = readFile("email.html");
|
||||||
recoveryCodeEmailMessage = readFile("recovery_code_email.html");
|
recoveryCodeEmailMessage = readFile("recovery_code_email.html");
|
||||||
welcomeMessage = readFile("welcome.txt").split("\\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,6 +71,7 @@ public class SettingsMigrationService extends PlainMigrationService {
|
|||||||
| hasOldHelpHeaderProperty(resource)
|
| hasOldHelpHeaderProperty(resource)
|
||||||
| hasSupportOldPasswordProperty(resource)
|
| hasSupportOldPasswordProperty(resource)
|
||||||
| convertToRegistrationType(resource)
|
| convertToRegistrationType(resource)
|
||||||
|
| mergeAndMovePermissionGroupSettings(resource)
|
||||||
|| hasDeprecatedProperties(resource);
|
|| hasDeprecatedProperties(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +82,8 @@ public class SettingsMigrationService extends PlainMigrationService {
|
|||||||
"VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite",
|
"VeryGames", "settings.restrictions.allowAllCommandsIfRegistrationIsOptional", "DataSource.mySQLWebsite",
|
||||||
"Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping",
|
"Hooks.customAttributes", "Security.stop.kickPlayersBeforeStopping",
|
||||||
"settings.restrictions.keepCollisionsDisabled", "settings.forceCommands", "settings.forceCommandsAsConsole",
|
"settings.restrictions.keepCollisionsDisabled", "settings.forceCommands", "settings.forceCommandsAsConsole",
|
||||||
"settings.forceRegisterCommands", "settings.forceRegisterCommandsAsConsole"};
|
"settings.forceRegisterCommands", "settings.forceRegisterCommandsAsConsole",
|
||||||
|
"settings.sessions.sessionExpireOnIpChange"};
|
||||||
for (String deprecatedPath : deprecatedProperties) {
|
for (String deprecatedPath : deprecatedProperties) {
|
||||||
if (resource.contains(deprecatedPath)) {
|
if (resource.contains(deprecatedPath)) {
|
||||||
return true;
|
return true;
|
||||||
@ -251,6 +253,26 @@ public class SettingsMigrationService extends PlainMigrationService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean mergeAndMovePermissionGroupSettings(PropertyResource resource) {
|
||||||
|
boolean performedChanges;
|
||||||
|
|
||||||
|
// We have two old settings replaced by only one: move the first non-empty one
|
||||||
|
Property<String> oldUnloggedInGroup = newProperty("settings.security.unLoggedinGroup", "");
|
||||||
|
Property<String> oldRegisteredGroup = newProperty("GroupOptions.RegisteredPlayerGroup", "");
|
||||||
|
if (!oldUnloggedInGroup.getValue(resource).isEmpty()) {
|
||||||
|
performedChanges = moveProperty(oldUnloggedInGroup, PluginSettings.REGISTERED_GROUP, resource);
|
||||||
|
} else {
|
||||||
|
performedChanges = moveProperty(oldRegisteredGroup, PluginSettings.REGISTERED_GROUP, resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move paths of other old options
|
||||||
|
performedChanges |= moveProperty(newProperty("GroupOptions.UnregisteredPlayerGroup", ""),
|
||||||
|
PluginSettings.UNREGISTERED_GROUP, resource);
|
||||||
|
performedChanges |= moveProperty(newProperty("permission.EnablePermissionCheck", false),
|
||||||
|
PluginSettings.ENABLE_PERMISSION_CHECK, resource);
|
||||||
|
return performedChanges;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for an old property path and moves it to a new path if present.
|
* Checks for an old property path and moves it to a new path if present.
|
||||||
*
|
*
|
||||||
@ -264,9 +286,10 @@ public class SettingsMigrationService extends PlainMigrationService {
|
|||||||
Property<T> newProperty,
|
Property<T> newProperty,
|
||||||
PropertyResource resource) {
|
PropertyResource resource) {
|
||||||
if (resource.contains(oldProperty.getPath())) {
|
if (resource.contains(oldProperty.getPath())) {
|
||||||
|
if (resource.contains(newProperty.getPath())) {
|
||||||
ConsoleLogger.info("Detected deprecated property " + oldProperty.getPath());
|
ConsoleLogger.info("Detected deprecated property " + oldProperty.getPath());
|
||||||
if (!resource.contains(newProperty.getPath())) {
|
} else {
|
||||||
ConsoleLogger.info("Renamed " + oldProperty.getPath() + " to " + newProperty.getPath());
|
ConsoleLogger.info("Renaming " + oldProperty.getPath() + " to " + newProperty.getPath());
|
||||||
resource.setValue(newProperty.getPath(), oldProperty.getValue(resource));
|
resource.setValue(newProperty.getPath(), oldProperty.getValue(resource));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package fr.xephi.authme.settings;
|
package fr.xephi.authme.settings;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
|
||||||
import fr.xephi.authme.service.PluginHookService;
|
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.service.PluginHookService;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.util.FileUtils;
|
import fr.xephi.authme.util.FileUtils;
|
||||||
@ -43,11 +42,9 @@ public class SpawnLoader implements Reloadable {
|
|||||||
* @param pluginFolder The AuthMe data folder
|
* @param pluginFolder The AuthMe data folder
|
||||||
* @param settings The setting instance
|
* @param settings The setting instance
|
||||||
* @param pluginHookService The plugin hooks instance
|
* @param pluginHookService The plugin hooks instance
|
||||||
* @param dataSource The plugin auth database instance
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService,
|
SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService) {
|
||||||
DataSource dataSource) {
|
|
||||||
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
|
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
|
||||||
File spawnFile = new File(pluginFolder, "spawn.yml");
|
File spawnFile = new File(pluginFolder, "spawn.yml");
|
||||||
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
|
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
package fr.xephi.authme.settings;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.GeoIpService;
|
||||||
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import fr.xephi.authme.util.lazytags.Tag;
|
||||||
|
import fr.xephi.authme.util.lazytags.TagReplacer;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
|
||||||
|
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the welcome message (welcome.txt).
|
||||||
|
*/
|
||||||
|
public class WelcomeMessageConfiguration implements Reloadable {
|
||||||
|
|
||||||
|
@DataFolder
|
||||||
|
@Inject
|
||||||
|
private File pluginFolder;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Server server;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GeoIpService geoIpService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
|
/** List of all supported tags for the welcome message. */
|
||||||
|
private final List<Tag<Player>> availableTags = Arrays.asList(
|
||||||
|
createTag("&", () -> "\u00a7"),
|
||||||
|
createTag("{PLAYER}", pl -> pl.getName()),
|
||||||
|
createTag("{ONLINE}", () -> Integer.toString(bukkitService.getOnlinePlayers().size())),
|
||||||
|
createTag("{MAXPLAYERS}", () -> Integer.toString(server.getMaxPlayers())),
|
||||||
|
createTag("{IP}", pl -> PlayerUtils.getPlayerIp(pl)),
|
||||||
|
createTag("{LOGINS}", () -> Integer.toString(playerCache.getLogged())),
|
||||||
|
createTag("{WORLD}", pl -> pl.getWorld().getName()),
|
||||||
|
createTag("{SERVER}", () -> server.getServerName()),
|
||||||
|
createTag("{VERSION}", () -> server.getBukkitVersion()),
|
||||||
|
createTag("{COUNTRY}", pl -> geoIpService.getCountryName(PlayerUtils.getPlayerIp(pl))));
|
||||||
|
|
||||||
|
private TagReplacer<Player> messageSupplier;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
List<String> welcomeMessage = readWelcomeFile();
|
||||||
|
messageSupplier = TagReplacer.newReplacer(availableTags, welcomeMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the welcome message for the given player.
|
||||||
|
*
|
||||||
|
* @param player the player for whom the welcome message should be prepared
|
||||||
|
* @return the welcome message
|
||||||
|
*/
|
||||||
|
public List<String> getWelcomeMessage(Player player) {
|
||||||
|
return messageSupplier.getAdaptedMessages(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the lines of the welcome message file
|
||||||
|
*/
|
||||||
|
private List<String> readWelcomeFile() {
|
||||||
|
File welcomeFile = new File(pluginFolder, "welcome.txt");
|
||||||
|
if (copyFileFromResource(welcomeFile, "welcome.txt")) {
|
||||||
|
try {
|
||||||
|
return Files.readAllLines(welcomeFile.toPath(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Failed to read welcome.txt file:", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ConsoleLogger.warning("Failed to copy welcome.txt from JAR");
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
@ -5,13 +5,21 @@ import ch.jalu.configme.resource.YamlFileResource;
|
|||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.GeoIpService;
|
||||||
import fr.xephi.authme.util.FileUtils;
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import fr.xephi.authme.util.lazytags.Tag;
|
||||||
|
import fr.xephi.authme.util.lazytags.WrappedTagReplacer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages configurable commands to be run when various events occur.
|
* Manages configurable commands to be run when various events occur.
|
||||||
*/
|
*/
|
||||||
@ -19,15 +27,20 @@ public class CommandManager implements Reloadable {
|
|||||||
|
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
private final BukkitService bukkitService;
|
private final BukkitService bukkitService;
|
||||||
|
private final GeoIpService geoIpService;
|
||||||
private final CommandMigrationService commandMigrationService;
|
private final CommandMigrationService commandMigrationService;
|
||||||
|
private final List<Tag<Player>> availableTags = buildAvailableTags();
|
||||||
|
|
||||||
private CommandConfig commandConfig;
|
private WrappedTagReplacer<Command, Player> onJoinCommands;
|
||||||
|
private WrappedTagReplacer<Command, Player> onLoginCommands;
|
||||||
|
private WrappedTagReplacer<Command, Player> onRegisterCommands;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CommandManager(@DataFolder File dataFolder, BukkitService bukkitService,
|
CommandManager(@DataFolder File dataFolder, BukkitService bukkitService, GeoIpService geoIpService,
|
||||||
CommandMigrationService commandMigrationService) {
|
CommandMigrationService commandMigrationService) {
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
this.bukkitService = bukkitService;
|
this.bukkitService = bukkitService;
|
||||||
|
this.geoIpService = geoIpService;
|
||||||
this.commandMigrationService = commandMigrationService;
|
this.commandMigrationService = commandMigrationService;
|
||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
@ -38,7 +51,7 @@ public class CommandManager implements Reloadable {
|
|||||||
* @param player the joining player
|
* @param player the joining player
|
||||||
*/
|
*/
|
||||||
public void runCommandsOnJoin(Player player) {
|
public void runCommandsOnJoin(Player player) {
|
||||||
executeCommands(player, commandConfig.getOnJoin());
|
executeCommands(player, onJoinCommands.getAdaptedItems(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,7 +60,7 @@ public class CommandManager implements Reloadable {
|
|||||||
* @param player the player who has registered
|
* @param player the player who has registered
|
||||||
*/
|
*/
|
||||||
public void runCommandsOnRegister(Player player) {
|
public void runCommandsOnRegister(Player player) {
|
||||||
executeCommands(player, commandConfig.getOnRegister());
|
executeCommands(player, onRegisterCommands.getAdaptedItems(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,12 +69,12 @@ public class CommandManager implements Reloadable {
|
|||||||
* @param player the player that logged in
|
* @param player the player that logged in
|
||||||
*/
|
*/
|
||||||
public void runCommandsOnLogin(Player player) {
|
public void runCommandsOnLogin(Player player) {
|
||||||
executeCommands(player, commandConfig.getOnLogin());
|
executeCommands(player, onLoginCommands.getAdaptedItems(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeCommands(Player player, Map<String, Command> commands) {
|
private void executeCommands(Player player, List<Command> commands) {
|
||||||
for (Command command : commands.values()) {
|
for (Command command : commands) {
|
||||||
final String execution = command.getCommand().replace("%p", player.getName());
|
final String execution = command.getCommand();
|
||||||
if (Executor.CONSOLE.equals(command.getExecutor())) {
|
if (Executor.CONSOLE.equals(command.getExecutor())) {
|
||||||
bukkitService.dispatchConsoleCommand(execution);
|
bukkitService.dispatchConsoleCommand(execution);
|
||||||
} else {
|
} else {
|
||||||
@ -77,8 +90,22 @@ public class CommandManager implements Reloadable {
|
|||||||
|
|
||||||
SettingsManager settingsManager = new SettingsManager(
|
SettingsManager settingsManager = new SettingsManager(
|
||||||
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
|
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
|
||||||
commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
|
CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
|
||||||
|
onJoinCommands = newReplacer(commandConfig.getOnJoin());
|
||||||
|
onLoginCommands = newReplacer(commandConfig.getOnLogin());
|
||||||
|
onRegisterCommands = newReplacer(commandConfig.getOnRegister());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WrappedTagReplacer<Command, Player> newReplacer(Map<String, Command> commands) {
|
||||||
|
return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand,
|
||||||
|
(cmd, text) -> new Command(text, cmd.getExecutor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Tag<Player>> buildAvailableTags() {
|
||||||
|
return Arrays.asList(
|
||||||
|
createTag("%p", pl -> pl.getName()),
|
||||||
|
createTag("%nick", pl -> pl.getDisplayName()),
|
||||||
|
createTag("%ip", pl -> PlayerUtils.getPlayerIp(pl)),
|
||||||
|
createTag("%country", pl -> geoIpService.getCountryName(PlayerUtils.getPlayerIp(pl))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,12 @@ public final class CommandSettingsHolder implements SettingsHolder {
|
|||||||
public static Map<String, String[]> sectionComments() {
|
public static Map<String, String[]> sectionComments() {
|
||||||
String[] comments = {
|
String[] comments = {
|
||||||
"This configuration file allows you to execute commands on various events.",
|
"This configuration file allows you to execute commands on various events.",
|
||||||
"%p in commands will be replaced with the player name.",
|
"Supported placeholders in commands:",
|
||||||
|
" %p is replaced with the player name.",
|
||||||
|
" %nick is replaced with the player's nick name",
|
||||||
|
" %ip is replaced with the player's IP address",
|
||||||
|
" %country is replaced with the player's country",
|
||||||
|
"",
|
||||||
"For example, if you want to send a welcome message to a player who just registered:",
|
"For example, if you want to send a welcome message to a player who just registered:",
|
||||||
"onRegister:",
|
"onRegister:",
|
||||||
" welcome:",
|
" welcome:",
|
||||||
|
@ -6,7 +6,7 @@ import ch.jalu.configme.properties.Property;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class BackupSettings implements SettingsHolder {
|
public final class BackupSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Enable or disable automatic backup")
|
@Comment("Enable or disable automatic backup")
|
||||||
public static final Property<Boolean> ENABLED =
|
public static final Property<Boolean> ENABLED =
|
||||||
|
@ -6,7 +6,7 @@ import ch.jalu.configme.properties.Property;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class ConverterSettings implements SettingsHolder {
|
public final class ConverterSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Rakamak file name")
|
@Comment("Rakamak file name")
|
||||||
public static final Property<String> RAKAMAK_FILE_NAME =
|
public static final Property<String> RAKAMAK_FILE_NAME =
|
||||||
|
@ -7,10 +7,10 @@ import fr.xephi.authme.datasource.DataSourceType;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class DatabaseSettings implements SettingsHolder {
|
public final class DatabaseSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment({"What type of database do you want to use?",
|
@Comment({"What type of database do you want to use?",
|
||||||
"Valid values: sqlite, mysql"})
|
"Valid values: SQLITE, MYSQL"})
|
||||||
public static final Property<DataSourceType> BACKEND =
|
public static final Property<DataSourceType> BACKEND =
|
||||||
newProperty(DataSourceType.class, "DataSource.backend", DataSourceType.SQLITE);
|
newProperty(DataSourceType.class, "DataSource.backend", DataSourceType.SQLITE);
|
||||||
|
|
||||||
@ -26,11 +26,15 @@ public class DatabaseSettings implements SettingsHolder {
|
|||||||
public static final Property<String> MYSQL_PORT =
|
public static final Property<String> MYSQL_PORT =
|
||||||
newProperty("DataSource.mySQLPort", "3306");
|
newProperty("DataSource.mySQLPort", "3306");
|
||||||
|
|
||||||
@Comment("Username about Database Connection Infos")
|
@Comment("Connect to MySQL database over SSL")
|
||||||
|
public static final Property<Boolean> MYSQL_USE_SSL =
|
||||||
|
newProperty("DataSource.mySQLUseSSL", true);
|
||||||
|
|
||||||
|
@Comment("Username to connect to the MySQL database")
|
||||||
public static final Property<String> MYSQL_USERNAME =
|
public static final Property<String> MYSQL_USERNAME =
|
||||||
newProperty("DataSource.mySQLUsername", "authme");
|
newProperty("DataSource.mySQLUsername", "authme");
|
||||||
|
|
||||||
@Comment("Password about Database Connection Infos")
|
@Comment("Password to connect to the MySQL database")
|
||||||
public static final Property<String> MYSQL_PASSWORD =
|
public static final Property<String> MYSQL_PASSWORD =
|
||||||
newProperty("DataSource.mySQLPassword", "12345");
|
newProperty("DataSource.mySQLPassword", "12345");
|
||||||
|
|
||||||
@ -58,10 +62,6 @@ public class DatabaseSettings implements SettingsHolder {
|
|||||||
public static final Property<String> MYSQL_COL_PASSWORD =
|
public static final Property<String> MYSQL_COL_PASSWORD =
|
||||||
newProperty("DataSource.mySQLColumnPassword", "password");
|
newProperty("DataSource.mySQLColumnPassword", "password");
|
||||||
|
|
||||||
@Comment("Request mysql over SSL")
|
|
||||||
public static final Property<Boolean> MYSQL_USE_SSL =
|
|
||||||
newProperty("DataSource.mySQLUseSSL", true);
|
|
||||||
|
|
||||||
@Comment("Column for storing players passwords salts")
|
@Comment("Column for storing players passwords salts")
|
||||||
public static final Property<String> MYSQL_COL_SALT =
|
public static final Property<String> MYSQL_COL_SALT =
|
||||||
newProperty("ExternalBoardOptions.mySQLColumnSalt", "");
|
newProperty("ExternalBoardOptions.mySQLColumnSalt", "");
|
||||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||||||
import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class EmailSettings implements SettingsHolder {
|
public final class EmailSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Email SMTP server host")
|
@Comment("Email SMTP server host")
|
||||||
public static final Property<String> SMTP_HOST =
|
public static final Property<String> SMTP_HOST =
|
||||||
@ -19,6 +19,10 @@ public class EmailSettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> SMTP_PORT =
|
public static final Property<Integer> SMTP_PORT =
|
||||||
newProperty("Email.mailPort", 465);
|
newProperty("Email.mailPort", 465);
|
||||||
|
|
||||||
|
@Comment("Only affects port 25: enable TLS/STARTTLS?")
|
||||||
|
public static final Property<Boolean> PORT25_USE_TLS =
|
||||||
|
newProperty("Email.useTls", true);
|
||||||
|
|
||||||
@Comment("Email account which sends the mails")
|
@Comment("Email account which sends the mails")
|
||||||
public static final Property<String> MAIL_ACCOUNT =
|
public static final Property<String> MAIL_ACCOUNT =
|
||||||
newProperty("Email.mailAccount", "");
|
newProperty("Email.mailAccount", "");
|
||||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||||||
import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class HooksSettings implements SettingsHolder {
|
public final class HooksSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Do we need to hook with multiverse for spawn checking?")
|
@Comment("Do we need to hook with multiverse for spawn checking?")
|
||||||
public static final Property<Boolean> MULTIVERSE =
|
public static final Property<Boolean> MULTIVERSE =
|
||||||
@ -54,17 +54,22 @@ public class HooksSettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> PHPBB_ACTIVATED_GROUP_ID =
|
public static final Property<Integer> PHPBB_ACTIVATED_GROUP_ID =
|
||||||
newProperty("ExternalBoardOptions.phpbbActivatedGroupId", 2);
|
newProperty("ExternalBoardOptions.phpbbActivatedGroupId", 2);
|
||||||
|
|
||||||
|
@Comment("IP Board table prefix defined during the IP Board installation process")
|
||||||
|
public static final Property<String> IPB_TABLE_PREFIX =
|
||||||
|
newProperty("ExternalBoardOptions.IPBTablePrefix", "ipb_");
|
||||||
|
|
||||||
|
@Comment("IP Board default group ID; 3 is the default registered group defined by IP Board")
|
||||||
|
public static final Property<Integer> IPB_ACTIVATED_GROUP_ID =
|
||||||
|
newProperty("ExternalBoardOptions.IPBActivatedGroupId", 3);
|
||||||
|
|
||||||
|
@Comment("XenForo default group ID; 2 is the default registered group defined by Xenforo")
|
||||||
|
public static final Property<Integer> XF_ACTIVATED_GROUP_ID =
|
||||||
|
newProperty("ExternalBoardOptions.XFActivatedGroupId", 2);
|
||||||
|
|
||||||
@Comment("Wordpress prefix defined during WordPress installation")
|
@Comment("Wordpress prefix defined during WordPress installation")
|
||||||
public static final Property<String> WORDPRESS_TABLE_PREFIX =
|
public static final Property<String> WORDPRESS_TABLE_PREFIX =
|
||||||
newProperty("ExternalBoardOptions.wordpressTablePrefix", "wp_");
|
newProperty("ExternalBoardOptions.wordpressTablePrefix", "wp_");
|
||||||
|
|
||||||
@Comment("Unregistered permission group")
|
|
||||||
public static final Property<String> UNREGISTERED_GROUP =
|
|
||||||
newProperty("GroupOptions.UnregisteredPlayerGroup", "");
|
|
||||||
|
|
||||||
@Comment("Registered permission group")
|
|
||||||
public static final Property<String> REGISTERED_GROUP =
|
|
||||||
newProperty("GroupOptions.RegisteredPlayerGroup", "");
|
|
||||||
|
|
||||||
private HooksSettings() {
|
private HooksSettings() {
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import fr.xephi.authme.output.LogLevel;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class PluginSettings implements SettingsHolder {
|
public final class PluginSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Do you want to enable the session feature?",
|
"Do you want to enable the session feature?",
|
||||||
@ -22,20 +22,11 @@ public class PluginSettings implements SettingsHolder {
|
|||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"After how many minutes should a session expire?",
|
"After how many minutes should a session expire?",
|
||||||
"Remember that sessions will end only after the timeout, and",
|
"A player's session ends after the timeout or if his IP has changed"
|
||||||
"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"
|
|
||||||
})
|
})
|
||||||
public static final Property<Integer> SESSIONS_TIMEOUT =
|
public static final Property<Integer> SESSIONS_TIMEOUT =
|
||||||
newProperty("settings.sessions.timeout", 10);
|
newProperty("settings.sessions.timeout", 10);
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"Should the session expire if the player tries to log in with",
|
|
||||||
"another IP address?"
|
|
||||||
})
|
|
||||||
public static final Property<Boolean> SESSIONS_EXPIRE_ON_IP_CHANGE =
|
|
||||||
newProperty("settings.sessions.sessionExpireOnIpChange", true);
|
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Message language, available languages:",
|
"Message language, available languages:",
|
||||||
"https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md"
|
"https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md"
|
||||||
@ -44,13 +35,33 @@ public class PluginSettings implements SettingsHolder {
|
|||||||
newProperty("settings.messagesLanguage", "en");
|
newProperty("settings.messagesLanguage", "en");
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Take care with this option; if you want",
|
"Enables switching a player to defined permission groups before they log in.",
|
||||||
"to use group switching of AuthMe",
|
"See below for a detailed explanation."
|
||||||
"for unloggedIn players, set this setting to true.",
|
|
||||||
"Default is false."
|
|
||||||
})
|
})
|
||||||
public static final Property<Boolean> ENABLE_PERMISSION_CHECK =
|
public static final Property<Boolean> ENABLE_PERMISSION_CHECK =
|
||||||
newProperty("permission.EnablePermissionCheck", false);
|
newProperty("GroupOptions.enablePermissionCheck", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"This is a very important option: if a registered player joins the server",
|
||||||
|
"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 login, the 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: registeredPlayerGroup: 'NotLogged'"
|
||||||
|
})
|
||||||
|
public static final Property<String> REGISTERED_GROUP =
|
||||||
|
newProperty("GroupOptions.registeredPlayerGroup", "");
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Similar to above, unregistered players can be set to the following",
|
||||||
|
"permissions group"
|
||||||
|
})
|
||||||
|
public static final Property<String> UNREGISTERED_GROUP =
|
||||||
|
newProperty("GroupOptions.unregisteredPlayerGroup", "");
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Log level: INFO, FINE, DEBUG. Use INFO for general messages,",
|
"Log level: INFO, FINE, DEBUG. Use INFO for general messages,",
|
||||||
|
@ -10,7 +10,7 @@ import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
|||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
|
|
||||||
public class ProtectionSettings implements SettingsHolder {
|
public final class ProtectionSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Enable some servers protection (country based login, antibot)")
|
@Comment("Enable some servers protection (country based login, antibot)")
|
||||||
public static final Property<Boolean> ENABLE_PROTECTION =
|
public static final Property<Boolean> ENABLE_PROTECTION =
|
||||||
|
@ -6,7 +6,7 @@ import ch.jalu.configme.properties.Property;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class PurgeSettings implements SettingsHolder {
|
public final class PurgeSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("If enabled, AuthMe automatically purges old, unused accounts")
|
@Comment("If enabled, AuthMe automatically purges old, unused accounts")
|
||||||
public static final Property<Boolean> USE_AUTO_PURGE =
|
public static final Property<Boolean> USE_AUTO_PURGE =
|
||||||
|
@ -8,7 +8,7 @@ import fr.xephi.authme.process.register.RegistrationType;
|
|||||||
|
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class RegistrationSettings implements SettingsHolder {
|
public final class RegistrationSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment("Enable registration on the server?")
|
@Comment("Enable registration on the server?")
|
||||||
public static final Property<Boolean> IS_ENABLED =
|
public static final Property<Boolean> IS_ENABLED =
|
||||||
@ -42,7 +42,8 @@ public class RegistrationSettings implements SettingsHolder {
|
|||||||
"EMAIL_MANDATORY = for password register: 2nd argument MUST be an email address"
|
"EMAIL_MANDATORY = for password register: 2nd argument MUST be an email address"
|
||||||
})
|
})
|
||||||
public static final Property<RegisterSecondaryArgument> REGISTER_SECOND_ARGUMENT =
|
public static final Property<RegisterSecondaryArgument> REGISTER_SECOND_ARGUMENT =
|
||||||
newProperty(RegisterSecondaryArgument.class, "settings.registration.secondArg", RegisterSecondaryArgument.CONFIRMATION);
|
newProperty(RegisterSecondaryArgument.class, "settings.registration.secondArg",
|
||||||
|
RegisterSecondaryArgument.CONFIRMATION);
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Do we force kick a player after a successful registration?",
|
"Do we force kick a player after a successful registration?",
|
||||||
|
@ -10,7 +10,7 @@ import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
|
|||||||
import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseListProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseListProperty;
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class RestrictionSettings implements SettingsHolder {
|
public final class RestrictionSettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Can not authenticated players chat?",
|
"Can not authenticated players chat?",
|
||||||
@ -81,9 +81,13 @@ public class RestrictionSettings implements SettingsHolder {
|
|||||||
"Example:",
|
"Example:",
|
||||||
" AllowedRestrictedUser:",
|
" AllowedRestrictedUser:",
|
||||||
" - playername;127.0.0.1"})
|
" - playername;127.0.0.1"})
|
||||||
public static final Property<List<String>> ALLOWED_RESTRICTED_USERS =
|
public static final Property<List<String>> RESTRICTED_USERS =
|
||||||
newLowercaseListProperty("settings.restrictions.AllowedRestrictedUser");
|
newLowercaseListProperty("settings.restrictions.AllowedRestrictedUser");
|
||||||
|
|
||||||
|
@Comment("Ban unknown IPs trying to log in with a restricted username?")
|
||||||
|
public static final Property<Boolean> BAN_UNKNOWN_IP =
|
||||||
|
newProperty("settings.restrictions.banUnsafedIP", false);
|
||||||
|
|
||||||
@Comment("Should unregistered players be kicked immediately?")
|
@Comment("Should unregistered players be kicked immediately?")
|
||||||
public static final Property<Boolean> KICK_NON_REGISTERED =
|
public static final Property<Boolean> KICK_NON_REGISTERED =
|
||||||
newProperty("settings.restrictions.kickNonRegistered", false);
|
newProperty("settings.restrictions.kickNonRegistered", false);
|
||||||
@ -115,7 +119,7 @@ public class RestrictionSettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> TIMEOUT =
|
public static final Property<Integer> TIMEOUT =
|
||||||
newProperty("settings.restrictions.timeout", 30);
|
newProperty("settings.restrictions.timeout", 30);
|
||||||
|
|
||||||
@Comment("Regex syntax of allowed characters in the player name.")
|
@Comment("Regex pattern of allowed characters in the player name.")
|
||||||
public static final Property<String> ALLOWED_NICKNAME_CHARACTERS =
|
public static final Property<String> ALLOWED_NICKNAME_CHARACTERS =
|
||||||
newProperty("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*");
|
newProperty("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*");
|
||||||
|
|
||||||
@ -140,10 +144,6 @@ public class RestrictionSettings implements SettingsHolder {
|
|||||||
public static final Property<Boolean> DISPLAY_OTHER_ACCOUNTS =
|
public static final Property<Boolean> DISPLAY_OTHER_ACCOUNTS =
|
||||||
newProperty("settings.restrictions.displayOtherAccounts", true);
|
newProperty("settings.restrictions.displayOtherAccounts", true);
|
||||||
|
|
||||||
@Comment("Ban ip when the ip is not the ip registered in database")
|
|
||||||
public static final Property<Boolean> BAN_UNKNOWN_IP =
|
|
||||||
newProperty("settings.restrictions.banUnsafedIP", false);
|
|
||||||
|
|
||||||
@Comment("Spawn priority; values: authme, essentials, multiverse, default")
|
@Comment("Spawn priority; values: authme, essentials, multiverse, default")
|
||||||
public static final Property<String> SPAWN_PRIORITY =
|
public static final Property<String> SPAWN_PRIORITY =
|
||||||
newProperty("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default");
|
newProperty("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default");
|
||||||
|
@ -12,7 +12,7 @@ import java.util.Set;
|
|||||||
import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseListProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseListProperty;
|
||||||
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||||
|
|
||||||
public class SecuritySettings implements SettingsHolder {
|
public final class SecuritySettings implements SettingsHolder {
|
||||||
|
|
||||||
@Comment({"Stop the server if we can't contact the sql database",
|
@Comment({"Stop the server if we can't contact the sql database",
|
||||||
"Take care with this, if you set this to false,",
|
"Take care with this, if you set this to false,",
|
||||||
@ -40,6 +40,10 @@ public class SecuritySettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> CAPTCHA_LENGTH =
|
public static final Property<Integer> CAPTCHA_LENGTH =
|
||||||
newProperty("Security.captcha.captchaLength", 5);
|
newProperty("Security.captcha.captchaLength", 5);
|
||||||
|
|
||||||
|
@Comment("Minutes after which login attempts count is reset for a player")
|
||||||
|
public static final Property<Integer> CAPTCHA_COUNT_MINUTES_BEFORE_RESET =
|
||||||
|
newProperty("Security.captcha.captchaCountReset", 60);
|
||||||
|
|
||||||
@Comment("Minimum length of password")
|
@Comment("Minimum length of password")
|
||||||
public static final Property<Integer> MIN_PASSWORD_LENGTH =
|
public static final Property<Integer> MIN_PASSWORD_LENGTH =
|
||||||
newProperty("settings.security.minPasswordLength", 5);
|
newProperty("settings.security.minPasswordLength", 5);
|
||||||
@ -48,22 +52,6 @@ public class SecuritySettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> MAX_PASSWORD_LENGTH =
|
public static final Property<Integer> MAX_PASSWORD_LENGTH =
|
||||||
newProperty("settings.security.passwordMaxLength", 30);
|
newProperty("settings.security.passwordMaxLength", 30);
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"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"
|
|
||||||
})
|
|
||||||
public static final Property<String> UNLOGGEDIN_GROUP =
|
|
||||||
newProperty("settings.security.unLoggedinGroup", "unLoggedinGroup");
|
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,",
|
"Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,",
|
||||||
"MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,",
|
"MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,",
|
||||||
@ -98,7 +86,8 @@ public class SecuritySettings implements SettingsHolder {
|
|||||||
"- 'password'",
|
"- 'password'",
|
||||||
"- 'help'"})
|
"- 'help'"})
|
||||||
public static final Property<List<String>> UNSAFE_PASSWORDS =
|
public static final Property<List<String>> UNSAFE_PASSWORDS =
|
||||||
newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789", "help");
|
newLowercaseListProperty("settings.security.unsafePasswords",
|
||||||
|
"123456", "password", "qwerty", "12345", "54321", "123456789", "help");
|
||||||
|
|
||||||
@Comment("Tempban a user's IP address if they enter the wrong password too many times")
|
@Comment("Tempban a user's IP address if they enter the wrong password too many times")
|
||||||
public static final Property<Boolean> TEMPBAN_ON_MAX_LOGINS =
|
public static final Property<Boolean> TEMPBAN_ON_MAX_LOGINS =
|
||||||
@ -126,6 +115,13 @@ public class SecuritySettings implements SettingsHolder {
|
|||||||
public static final Property<Integer> RECOVERY_CODE_HOURS_VALID =
|
public static final Property<Integer> RECOVERY_CODE_HOURS_VALID =
|
||||||
newProperty("Security.recoveryCode.validForHours", 4);
|
newProperty("Security.recoveryCode.validForHours", 4);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Seconds a user has to wait for before a password recovery mail may be sent again",
|
||||||
|
"This prevents an attacker from abusing AuthMe's email feature."
|
||||||
|
})
|
||||||
|
public static final Property<Integer> EMAIL_RECOVERY_COOLDOWN_SECONDS =
|
||||||
|
newProperty("Security.emailRecovery.cooldown", 60);
|
||||||
|
|
||||||
private SecuritySettings() {
|
private SecuritySettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,20 +3,19 @@ package fr.xephi.authme.task.purge;
|
|||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.PurgeSettings;
|
import fr.xephi.authme.settings.properties.PurgeSettings;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.util.Utils;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
// TODO: move into services. -sgdc3
|
import static fr.xephi.authme.util.Utils.logAndSendMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates purge tasks.
|
* Initiates purge tasks.
|
||||||
@ -75,7 +74,7 @@ public class PurgeService {
|
|||||||
public void runPurge(CommandSender sender, long until, boolean includeEntriesWithLastLoginZero) {
|
public void runPurge(CommandSender sender, long until, boolean includeEntriesWithLastLoginZero) {
|
||||||
//todo: note this should may run async because it may executes a SQL-Query
|
//todo: note this should may run async because it may executes a SQL-Query
|
||||||
Set<String> toPurge = dataSource.getRecordsToPurge(until, includeEntriesWithLastLoginZero);
|
Set<String> toPurge = dataSource.getRecordsToPurge(until, includeEntriesWithLastLoginZero);
|
||||||
if (CollectionUtils.isEmpty(toPurge)) {
|
if (Utils.isCollectionEmpty(toPurge)) {
|
||||||
logAndSendMessage(sender, "No players to purge");
|
logAndSendMessage(sender, "No players to purge");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -119,12 +118,4 @@ public class PurgeService {
|
|||||||
void executePurge(Collection<OfflinePlayer> players, Collection<String> names) {
|
void executePurge(Collection<OfflinePlayer> players, Collection<String> names) {
|
||||||
purgeExecutor.executePurge(players, names);
|
purgeExecutor.executePurge(players, names);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logAndSendMessage(CommandSender sender, String message) {
|
|
||||||
ConsoleLogger.info(message);
|
|
||||||
// Make sure sender is not console user, which will see the message from ConsoleLogger already
|
|
||||||
if (sender != null && !(sender instanceof ConsoleCommandSender)) {
|
|
||||||
sender.sendMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
package fr.xephi.authme.util;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utils class for collections.
|
|
||||||
*/
|
|
||||||
public final class CollectionUtils {
|
|
||||||
|
|
||||||
// Utility class
|
|
||||||
private CollectionUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a range from a list based on start and count parameters in a safe way.
|
|
||||||
*
|
|
||||||
* @param <T> element
|
|
||||||
* @param list The List
|
|
||||||
* @param start The start index
|
|
||||||
* @param count The number of elements to add
|
|
||||||
*
|
|
||||||
* @return The sublist consisting at most of {@code count} elements (less if the parameters
|
|
||||||
* exceed the size of the list)
|
|
||||||
*/
|
|
||||||
public static <T> List<T> getRange(List<T> list, int start, int count) {
|
|
||||||
if (start >= list.size() || count <= 0) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
} else if (start < 0) {
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
int end = Math.min(list.size(), start + count);
|
|
||||||
return list.subList(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all elements from a list starting from the given index.
|
|
||||||
*
|
|
||||||
* @param <T> element
|
|
||||||
* @param list The List
|
|
||||||
* @param start The start index
|
|
||||||
*
|
|
||||||
* @return The sublist of all elements from index {@code start} and on; empty list
|
|
||||||
* if the start index exceeds the list's size
|
|
||||||
*/
|
|
||||||
public static <T> List<T> getRange(List<T> list, int start) {
|
|
||||||
if (start >= list.size()) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
return getRange(list, start, list.size() - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Null-safe way to check whether a collection is empty or not.
|
|
||||||
*
|
|
||||||
* @param coll The collection to verify
|
|
||||||
* @return True if the collection is null or empty, false otherwise
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(Collection<?> coll) {
|
|
||||||
return coll == null || coll.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,7 @@ import org.bukkit.entity.Player;
|
|||||||
/**
|
/**
|
||||||
* Player utilities.
|
* Player utilities.
|
||||||
*/
|
*/
|
||||||
public class PlayerUtils {
|
public final class PlayerUtils {
|
||||||
|
|
||||||
// Utility class
|
// Utility class
|
||||||
private PlayerUtils() {
|
private PlayerUtils() {
|
||||||
|
@ -8,7 +8,7 @@ import java.util.Random;
|
|||||||
*/
|
*/
|
||||||
public final class RandomStringUtils {
|
public final class RandomStringUtils {
|
||||||
|
|
||||||
private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
private static final char[] CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
|
||||||
private static final Random RANDOM = new SecureRandom();
|
private static final Random RANDOM = new SecureRandom();
|
||||||
private static final int HEX_MAX_INDEX = 16;
|
private static final int HEX_MAX_INDEX = 16;
|
||||||
private static final int LOWER_ALPHANUMERIC_INDEX = 36;
|
private static final int LOWER_ALPHANUMERIC_INDEX = 36;
|
||||||
@ -24,7 +24,7 @@ public final class RandomStringUtils {
|
|||||||
* @return The random string
|
* @return The random string
|
||||||
*/
|
*/
|
||||||
public static String generate(int length) {
|
public static String generate(int length) {
|
||||||
return generate(length, LOWER_ALPHANUMERIC_INDEX);
|
return generateString(length, LOWER_ALPHANUMERIC_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +35,7 @@ public final class RandomStringUtils {
|
|||||||
* @return The random hexadecimal string
|
* @return The random hexadecimal string
|
||||||
*/
|
*/
|
||||||
public static String generateHex(int length) {
|
public static String generateHex(int length) {
|
||||||
return generate(length, HEX_MAX_INDEX);
|
return generateString(length, HEX_MAX_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,16 +46,16 @@ public final class RandomStringUtils {
|
|||||||
* @return The random string
|
* @return The random string
|
||||||
*/
|
*/
|
||||||
public static String generateLowerUpper(int length) {
|
public static String generateLowerUpper(int length) {
|
||||||
return generate(length, CHARS.length());
|
return generateString(length, CHARS.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generate(int length, int maxIndex) {
|
private static String generateString(int length, int maxIndex) {
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
throw new IllegalArgumentException("Length must be positive but was " + length);
|
throw new IllegalArgumentException("Length must be positive but was " + length);
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder(length);
|
StringBuilder sb = new StringBuilder(length);
|
||||||
for (int i = 0; i < length; ++i) {
|
for (int i = 0; i < length; ++i) {
|
||||||
sb.append(CHARS.charAt(RANDOM.nextInt(maxIndex)));
|
sb.append(CHARS[RANDOM.nextInt(maxIndex)]);
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public final class StringUtils {
|
|||||||
*
|
*
|
||||||
* @return True if the string contains at least one of the items
|
* @return True if the string contains at least one of the items
|
||||||
*/
|
*/
|
||||||
public static boolean containsAny(String str, String... pieces) {
|
public static boolean containsAny(String str, Iterable<String> pieces) {
|
||||||
if (str == null) {
|
if (str == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -76,4 +76,20 @@ public final class StringUtils {
|
|||||||
public static String formatException(Throwable th) {
|
public static String formatException(Throwable th) {
|
||||||
return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage();
|
return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the given needle is in the middle of the haystack, i.e. that the haystack
|
||||||
|
* contains the needle and that it is not at the very start or end.
|
||||||
|
*
|
||||||
|
* @param needle the needle to search for
|
||||||
|
* @param haystack the haystack to search in
|
||||||
|
*
|
||||||
|
* @return true if the needle is in the middle of the word, false otherwise
|
||||||
|
*/
|
||||||
|
// Note ljacqu 20170314: `needle` is restricted to char type intentionally because something like
|
||||||
|
// isInsideString("11", "2211") would unexpectedly return true...
|
||||||
|
public static boolean isInsideString(char needle, String haystack) {
|
||||||
|
int index = haystack.indexOf(needle);
|
||||||
|
return index > 0 && index < haystack.length() - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package fr.xephi.authme.util;
|
package fr.xephi.authme.util;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +53,32 @@ public final class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the given sender (null safe), and logs the message to the console.
|
||||||
|
* This method is aware that the command sender might be the console sender and avoids
|
||||||
|
* displaying the message twice in this case.
|
||||||
|
*
|
||||||
|
* @param sender the sender to inform
|
||||||
|
* @param message the message to log and send
|
||||||
|
*/
|
||||||
|
public static void logAndSendMessage(CommandSender sender, String message) {
|
||||||
|
ConsoleLogger.info(message);
|
||||||
|
// Make sure sender is not console user, which will see the message from ConsoleLogger already
|
||||||
|
if (sender != null && !(sender instanceof ConsoleCommandSender)) {
|
||||||
|
sender.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null-safe way to check whether a collection is empty or not.
|
||||||
|
*
|
||||||
|
* @param coll The collection to verify
|
||||||
|
* @return True if the collection is null or empty, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isCollectionEmpty(Collection<?> coll) {
|
||||||
|
return coll == null || coll.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the available core count of the JVM.
|
* Return the available core count of the JVM.
|
||||||
*
|
*
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user