Merge branches 'master' and 'passwd_recovery_process' of https://github.com/AuthMe/AuthMeReloaded into passwd_recovery_process
# Conflicts: # docs/config.md # src/main/resources/messages/messages_bg.yml # src/main/resources/messages/messages_es.yml # src/main/resources/messages/messages_pt.yml # src/main/resources/messages/messages_zhcn.yml
This commit is contained in:
commit
9d21eefc74
@ -145,7 +145,7 @@
|
|||||||
<property name="scope" value="package"/>
|
<property name="scope" value="package"/>
|
||||||
<property name="allowMissingThrowsTags" value="true"/>
|
<property name="allowMissingThrowsTags" value="true"/>
|
||||||
<property name="minLineCount" value="4"/>
|
<property name="minLineCount" value="4"/>
|
||||||
<property name="allowedAnnotations" value="Override, Test"/>
|
<property name="allowedAnnotations" value="Override, Test, SectionComments"/>
|
||||||
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/>
|
<property name="tokens" value="METHOD_DEF, ANNOTATION_FIELD_DEF"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="MethodName">
|
<module name="MethodName">
|
||||||
@ -159,6 +159,8 @@
|
|||||||
<module name="EmptyCatchBlock">
|
<module name="EmptyCatchBlock">
|
||||||
<property name="exceptionVariableName" value="ignore|ignored"/>
|
<property name="exceptionVariableName" value="ignore|ignored"/>
|
||||||
</module>
|
</module>
|
||||||
|
<module name="MissingOverride"/>
|
||||||
|
<module name="EqualsHashCode"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="FileTabCharacter"/>
|
<module name="FileTabCharacter"/>
|
||||||
</module>
|
</module>
|
||||||
|
|||||||
@ -25,4 +25,6 @@ exclude_paths:
|
|||||||
- 'src/main/java/fr/xephi/authme/mail/OAuth2SaslClient.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/mail/OAuth2SaslClientFactory.java'
|
||||||
- 'src/main/java/fr/xephi/authme/security/crypts/BCryptService.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/WHIRLPOOL.java'
|
||||||
|
- 'src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java'
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,7 +10,8 @@ MANIFEST.MF
|
|||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
|
||||||
|
# Mac OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
### Intellij ###
|
### Intellij ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
||||||
|
|||||||
14
README.md
14
README.md
@ -19,20 +19,14 @@
|
|||||||
- Project status:
|
- Project status:
|
||||||
- Dependencies: [](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
|
- Dependencies: [](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
|
||||||
- Test coverage: [](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
- Test coverage: [](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
||||||
|
- Code climate: [](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>
|
||||||
|
|||||||
@ -73,17 +73,6 @@ ExternalBoardOptions:
|
|||||||
phpbbActivatedGroupId: 2
|
phpbbActivatedGroupId: 2
|
||||||
# Wordpress prefix defined during WordPress installation
|
# Wordpress prefix defined during WordPress installation
|
||||||
wordpressTablePrefix: 'wp_'
|
wordpressTablePrefix: 'wp_'
|
||||||
Converter:
|
|
||||||
Rakamak:
|
|
||||||
# Rakamak file name
|
|
||||||
fileName: 'users.rak'
|
|
||||||
# Rakamak use IP?
|
|
||||||
useIP: false
|
|
||||||
# Rakamak IP file name
|
|
||||||
ipFileName: 'UsersIp.rak'
|
|
||||||
CrazyLogin:
|
|
||||||
# CrazyLogin database file name
|
|
||||||
fileName: 'accounts.db'
|
|
||||||
settings:
|
settings:
|
||||||
sessions:
|
sessions:
|
||||||
# Do you want to enable the session feature?
|
# Do you want to enable the session feature?
|
||||||
@ -452,6 +441,23 @@ Security:
|
|||||||
# Seconds a user has to wait for before a password recovery mail may be sent again
|
# 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.
|
# This prevents an attacker from abusing AuthMe's email feature.
|
||||||
cooldown: 60
|
cooldown: 60
|
||||||
|
# Before a user logs in, various properties are temporarily removed from the player,
|
||||||
|
# such as OP status, ability to fly, and walk/fly speed.
|
||||||
|
# Once the user is logged in, we add back the properties we previously saved.
|
||||||
|
# In this section, you may define how the properties should be restored.
|
||||||
|
limbo:
|
||||||
|
# Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE.
|
||||||
|
# RESTORE sets back the old property from the player.
|
||||||
|
restoreAllowFlight: 'RESTORE'
|
||||||
|
# Restore fly speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.
|
||||||
|
# RESTORE: restore the speed the player had;
|
||||||
|
# DEFAULT: always set to default speed;
|
||||||
|
# MAX_RESTORE: take the maximum of the player's current speed and the previous one
|
||||||
|
# RESTORE_NO_ZERO: Like 'restore' but sets speed to default if the player's speed was 0
|
||||||
|
restoreFlySpeed: 'MAX_RESTORE'
|
||||||
|
# Restore walk speed: RESTORE, DEFAULT, MAX_RESTORE, RESTORE_NO_ZERO.
|
||||||
|
# See above for a description of the values.
|
||||||
|
restoreWalkSpeed: 'MAX_RESTORE'
|
||||||
BackupSystem:
|
BackupSystem:
|
||||||
# Enable or disable automatic backup
|
# Enable or disable automatic backup
|
||||||
ActivateBackup: false
|
ActivateBackup: false
|
||||||
@ -461,6 +467,17 @@ BackupSystem:
|
|||||||
OnServerStop: true
|
OnServerStop: true
|
||||||
# Windows only mysql installation Path
|
# Windows only mysql installation Path
|
||||||
MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\'
|
MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\'
|
||||||
|
Converter:
|
||||||
|
Rakamak:
|
||||||
|
# Rakamak file name
|
||||||
|
fileName: 'users.rak'
|
||||||
|
# Rakamak use IP?
|
||||||
|
useIP: false
|
||||||
|
# Rakamak IP file name
|
||||||
|
ipFileName: 'UsersIp.rak'
|
||||||
|
CrazyLogin:
|
||||||
|
# CrazyLogin database file name
|
||||||
|
fileName: 'accounts.db'
|
||||||
```
|
```
|
||||||
|
|
||||||
To change settings on a running server, save your changes to config.yml and use
|
To change settings on a running server, save your changes to config.yml and use
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Tue Feb 28 19:25:18 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,25 +8,25 @@ 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 | 61% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=61&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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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 | 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 | 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 | 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 | 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 | 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" />
|
||||||
[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" />
|
[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 | 59% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=59&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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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 | 63% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=63&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 | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&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 | 63% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=63&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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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 | 64% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb7700&w=64&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 | 47% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa5500&w=47&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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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 | 77% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb9900&w=77&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 | 88% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=88&h=5&txtpad=1" alt="bar" />
|
[ro](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ro.yml) | Romanian | 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 | 89% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=88cc33&w=89&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 | 41% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aa4400&w=41&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 | 100% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=66ff66&w=100&h=5&txtpad=1" alt="bar" />
|
[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 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 | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
|
[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 83% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=aaaa11&w=83&h=5&txtpad=1" alt="bar" />
|
||||||
@ -36,7 +36,6 @@ Code | Language | Translated |
|
|||||||
[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" />
|
[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) | 72% | <img src="https://placeholdit.imgix.net/~text?txtsize=5&bg=bb8800&w=72&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 Tue Feb 28 19:25:18 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
|
||||||
|
|||||||
@ -15,6 +15,7 @@ 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.initialization.factory.FactoryDependencyHandler;
|
||||||
|
import fr.xephi.authme.initialization.factory.SingletonStoreDependencyHandler;
|
||||||
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;
|
||||||
@ -25,7 +26,7 @@ import fr.xephi.authme.listener.PlayerListener19;
|
|||||||
import fr.xephi.authme.listener.ServerListener;
|
import fr.xephi.authme.listener.ServerListener;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||||
import fr.xephi.authme.security.crypts.SHA256;
|
import fr.xephi.authme.security.crypts.Sha256;
|
||||||
import fr.xephi.authme.service.BackupService;
|
import fr.xephi.authme.service.BackupService;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.MigrationService;
|
import fr.xephi.authme.service.MigrationService;
|
||||||
@ -36,6 +37,7 @@ 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 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;
|
||||||
@ -195,12 +197,17 @@ 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()
|
injector = new InjectorBuilder()
|
||||||
.addHandlers(new FactoryDependencyHandler())
|
.addHandlers(new FactoryDependencyHandler(), new SingletonStoreDependencyHandler())
|
||||||
.addDefaultHandlers("fr.xephi.authme")
|
.addDefaultHandlers("fr.xephi.authme")
|
||||||
.create();
|
.create();
|
||||||
injector.register(AuthMe.class, this);
|
injector.register(AuthMe.class, this);
|
||||||
@ -220,7 +227,7 @@ public class AuthMe extends JavaPlugin {
|
|||||||
instantiateServices(injector);
|
instantiateServices(injector);
|
||||||
|
|
||||||
// Convert deprecated PLAINTEXT hash entries
|
// Convert deprecated PLAINTEXT hash entries
|
||||||
MigrationService.changePlainTextToSha256(settings, database, new SHA256());
|
MigrationService.changePlainTextToSha256(settings, database, new Sha256());
|
||||||
|
|
||||||
// TODO: does this still make sense? -sgdc3
|
// TODO: does this still make sense? -sgdc3
|
||||||
// If the server is empty (fresh start) just set all the players as unlogged
|
// If the server is empty (fresh start) just set all the players as unlogged
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -5,7 +5,8 @@ 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.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
|
import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams;
|
||||||
|
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
||||||
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.PluginHookService;
|
import fr.xephi.authme.service.PluginHookService;
|
||||||
@ -24,6 +25,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;
|
||||||
@ -34,15 +36,13 @@ public class NewAPI {
|
|||||||
private final Management management;
|
private final Management management;
|
||||||
private final ValidationService validationService;
|
private final ValidationService validationService;
|
||||||
private final PlayerCache playerCache;
|
private final PlayerCache playerCache;
|
||||||
private final RegistrationExecutorProvider registrationExecutorProvider;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor for NewAPI.
|
* Constructor for NewAPI.
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
NewAPI(AuthMe plugin, PluginHookService pluginHookService, DataSource dataSource, PasswordSecurity passwordSecurity,
|
NewAPI(AuthMe plugin, PluginHookService pluginHookService, DataSource dataSource, PasswordSecurity passwordSecurity,
|
||||||
Management management, ValidationService validationService, PlayerCache playerCache,
|
Management management, ValidationService validationService, PlayerCache playerCache) {
|
||||||
RegistrationExecutorProvider registrationExecutorProvider) {
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.pluginHookService = pluginHookService;
|
this.pluginHookService = pluginHookService;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
@ -50,7 +50,6 @@ public class NewAPI {
|
|||||||
this.management = management;
|
this.management = management;
|
||||||
this.validationService = validationService;
|
this.validationService = validationService;
|
||||||
this.playerCache = playerCache;
|
this.playerCache = playerCache;
|
||||||
this.registrationExecutorProvider = registrationExecutorProvider;
|
|
||||||
NewAPI.singleton = this;
|
NewAPI.singleton = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,8 +202,8 @@ public class NewAPI {
|
|||||||
* @param autoLogin Should the player be authenticated automatically after the registration?
|
* @param autoLogin Should the player be authenticated automatically after the registration?
|
||||||
*/
|
*/
|
||||||
public void forceRegister(Player player, String password, boolean autoLogin) {
|
public void forceRegister(Player player, String password, boolean autoLogin) {
|
||||||
management.performRegister(player,
|
management.performRegister(RegistrationMethod.API_REGISTRATION,
|
||||||
registrationExecutorProvider.getPasswordRegisterExecutor(player, password, autoLogin));
|
ApiPasswordRegisterParams.of(player, password, autoLogin));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import fr.xephi.authme.datasource.converter.MySqlToSqlite;
|
|||||||
import fr.xephi.authme.datasource.converter.RakamakConverter;
|
import fr.xephi.authme.datasource.converter.RakamakConverter;
|
||||||
import fr.xephi.authme.datasource.converter.RoyalAuthConverter;
|
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.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;
|
||||||
@ -78,11 +78,11 @@ public class ConverterCommand implements ExecutableCommand {
|
|||||||
*/
|
*/
|
||||||
private static Map<String, Class<? extends Converter>> getConverters() {
|
private static Map<String, Class<? extends Converter>> getConverters() {
|
||||||
return ImmutableMap.<String, Class<? extends Converter>>builder()
|
return ImmutableMap.<String, Class<? extends Converter>>builder()
|
||||||
.put("xauth", xAuthConverter.class)
|
.put("xauth", XAuthConverter.class)
|
||||||
.put("crazylogin", CrazyLoginConverter.class)
|
.put("crazylogin", CrazyLoginConverter.class)
|
||||||
.put("rakamak", RakamakConverter.class)
|
.put("rakamak", RakamakConverter.class)
|
||||||
.put("royalauth", RoyalAuthConverter.class)
|
.put("royalauth", RoyalAuthConverter.class)
|
||||||
.put("vauth", vAuthConverter.class)
|
.put("vauth", VAuthConverter.class)
|
||||||
.put("sqlitetosql", SqliteToSql.class)
|
.put("sqlitetosql", SqliteToSql.class)
|
||||||
.put("mysqltosqlite", MySqlToSqlite.class)
|
.put("mysqltosqlite", MySqlToSqlite.class)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
@ -38,9 +37,6 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboCache limboCache;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||||
// Get the player name and password
|
// Get the player name and password
|
||||||
@ -83,7 +79,6 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
|||||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
limboCache.restoreData(player);
|
|
||||||
player.kickPlayer(commonService.retrieveSingleMessage(MessageKey.KICK_FOR_ADMIN_REGISTER));
|
player.kickPlayer(commonService.retrieveSingleMessage(MessageKey.KICK_FOR_ADMIN_REGISTER));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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,72 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
|
import fr.xephi.authme.datasource.CacheDataSource;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.initialization.HasCleanup;
|
||||||
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
|
import fr.xephi.authme.initialization.factory.SingletonStore;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.applyToLimboPlayersMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches various statistics, particularly regarding in-memory data that is stored.
|
||||||
|
*/
|
||||||
|
class DataStatistics implements DebugSection {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboService limboService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SingletonStore<Object> singletonStore;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "stats";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Outputs general data statistics";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
sender.sendMessage("LimboPlayers in memory: " + applyToLimboPlayersMap(limboService, Map::size));
|
||||||
|
sender.sendMessage("PlayerCache size: " + playerCache.getLogged() + " (= logged in players)");
|
||||||
|
|
||||||
|
outputDatabaseStats(sender);
|
||||||
|
outputInjectorStats(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void outputDatabaseStats(CommandSender sender) {
|
||||||
|
sender.sendMessage("Total players in DB: " + dataSource.getAccountsRegistered());
|
||||||
|
sender.sendMessage("Total marked as logged in in DB: " + dataSource.getLoggedPlayers().size());
|
||||||
|
if (dataSource instanceof CacheDataSource) {
|
||||||
|
CacheDataSource cacheDataSource = (CacheDataSource) this.dataSource;
|
||||||
|
sender.sendMessage("Cached PlayerAuth objects: " + cacheDataSource.getCachedAuths().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void outputInjectorStats(CommandSender sender) {
|
||||||
|
sender.sendMessage(
|
||||||
|
String.format("Singleton Java classes: %d (Reloadable: %d / SettingsDependent: %d / HasCleanup: %d)",
|
||||||
|
singletonStore.retrieveAllOfType().size(),
|
||||||
|
singletonStore.retrieveAllOfType(Reloadable.class).size(),
|
||||||
|
singletonStore.retrieveAllOfType(SettingsDependent.class).size(),
|
||||||
|
singletonStore.retrieveAllOfType(HasCleanup.class).size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,10 +6,10 @@ import fr.xephi.authme.initialization.factory.Factory;
|
|||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug command main.
|
* Debug command main.
|
||||||
@ -19,8 +19,9 @@ public class DebugCommand implements ExecutableCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private Factory<DebugSection> debugSectionFactory;
|
private Factory<DebugSection> debugSectionFactory;
|
||||||
|
|
||||||
private Set<Class<? extends DebugSection>> sectionClasses =
|
private Set<Class<? extends DebugSection>> sectionClasses = ImmutableSet.of(PermissionGroups.class,
|
||||||
ImmutableSet.of(PermissionGroups.class, TestEmailSender.class);
|
DataStatistics.class, CountryLookup.class, PlayerAuthViewer.class, LimboPlayerViewer.class, CountryLookup.class,
|
||||||
|
HasPermissionChecker.class, TestEmailSender.class);
|
||||||
|
|
||||||
private Map<String, DebugSection> sections;
|
private Map<String, DebugSection> sections;
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ public class DebugCommand implements ExecutableCommand {
|
|||||||
// Lazy getter
|
// Lazy getter
|
||||||
private Map<String, DebugSection> getSections() {
|
private Map<String, DebugSection> getSections() {
|
||||||
if (sections == null) {
|
if (sections == null) {
|
||||||
Map<String, DebugSection> sections = new HashMap<>();
|
Map<String, DebugSection> sections = new TreeMap<>();
|
||||||
for (Class<? extends DebugSection> sectionClass : sectionClasses) {
|
for (Class<? extends DebugSection> sectionClass : sectionClasses) {
|
||||||
DebugSection section = debugSectionFactory.newInstance(sectionClass);
|
DebugSection section = debugSectionFactory.newInstance(sectionClass);
|
||||||
sections.put(section.getName(), section);
|
sections.put(section.getName(), section);
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities used within the DebugSection implementations.
|
||||||
|
*/
|
||||||
|
final class DebugSectionUtils {
|
||||||
|
|
||||||
|
private static Field limboEntriesField;
|
||||||
|
|
||||||
|
private DebugSectionUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the given location in a human readable way. Null-safe.
|
||||||
|
*
|
||||||
|
* @param location the location to format
|
||||||
|
* @return the formatted location
|
||||||
|
*/
|
||||||
|
static String formatLocation(Location location) {
|
||||||
|
if (location == null) {
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
String worldName = location.getWorld() == null ? "null" : location.getWorld().getName();
|
||||||
|
return formatLocation(location.getX(), location.getY(), location.getZ(), worldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the given location in a human readable way.
|
||||||
|
*
|
||||||
|
* @param x the x coordinate
|
||||||
|
* @param y the y coordinate
|
||||||
|
* @param z the z coordinate
|
||||||
|
* @param world the world name
|
||||||
|
* @return the formatted location
|
||||||
|
*/
|
||||||
|
static String formatLocation(double x, double y, double z, String world) {
|
||||||
|
return "(" + round(x) + ", " + round(y) + ", " + round(z) + ") in '" + world + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the given number to two decimals.
|
||||||
|
*
|
||||||
|
* @param number the number to round
|
||||||
|
* @return the rounded number
|
||||||
|
*/
|
||||||
|
private static String round(double number) {
|
||||||
|
DecimalFormat df = new DecimalFormat("#.##");
|
||||||
|
df.setRoundingMode(RoundingMode.HALF_UP);
|
||||||
|
return df.format(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Field getLimboPlayerEntriesField() {
|
||||||
|
if (limboEntriesField == null) {
|
||||||
|
try {
|
||||||
|
Field field = LimboService.class.getDeclaredField("entries");
|
||||||
|
field.setAccessible(true);
|
||||||
|
limboEntriesField = field;
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not retrieve LimboService entries field:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return limboEntriesField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the given function to the map in LimboService containing the LimboPlayers.
|
||||||
|
* As we don't want to expose this information in non-debug settings, this is done with reflection.
|
||||||
|
* Exceptions are generously caught and {@code null} is returned on failure.
|
||||||
|
*
|
||||||
|
* @param limboService the limbo service instance to get the map from
|
||||||
|
* @param function the function to apply to the map
|
||||||
|
* @param <U> the result type of the function
|
||||||
|
*
|
||||||
|
* @return player names for which there is a LimboPlayer (or error message upon failure)
|
||||||
|
*/
|
||||||
|
static <U> U applyToLimboPlayersMap(LimboService limboService, Function<Map, U> function) {
|
||||||
|
Field limboPlayerEntriesField = getLimboPlayerEntriesField();
|
||||||
|
if (limboPlayerEntriesField != null) {
|
||||||
|
try {
|
||||||
|
return function.apply((Map) limboEntriesField.get(limboService));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not retrieve LimboService values:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.permission.AdminPermission;
|
||||||
|
import fr.xephi.authme.permission.DefaultPermission;
|
||||||
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.permission.PlayerPermission;
|
||||||
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a player has a given permission, as checked by AuthMe.
|
||||||
|
*/
|
||||||
|
class HasPermissionChecker implements DebugSection {
|
||||||
|
|
||||||
|
static final List<Class<? extends PermissionNode>> PERMISSION_NODE_CLASSES =
|
||||||
|
Arrays.asList(AdminPermission.class, PlayerPermission.class, PlayerStatePermission.class);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "perm";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Checks if player has given permission: /authme debug perm bobby my.perm";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
if (arguments.size() < 2) {
|
||||||
|
sender.sendMessage("Check if a player has permission:");
|
||||||
|
sender.sendMessage("Example: /authme debug perm bobby my.perm.node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String playerName = arguments.get(0);
|
||||||
|
final String permissionNode = arguments.get(1);
|
||||||
|
|
||||||
|
Player player = bukkitService.getPlayerExact(playerName);
|
||||||
|
if (player == null) {
|
||||||
|
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
|
||||||
|
if (offlinePlayer == null) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "Player '" + playerName + "' does not exist");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Player '" + playerName + "' not online; checking with offline player");
|
||||||
|
performPermissionCheck(offlinePlayer, permissionNode, permissionsManager::hasPermissionOffline, sender);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
performPermissionCheck(player, permissionNode, permissionsManager::hasPermission, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a permission check and informs the given sender of the result. {@code permissionChecker} is the
|
||||||
|
* permission check to perform with the given {@code node} and the {@code player}.
|
||||||
|
*
|
||||||
|
* @param player the player to check a permission for
|
||||||
|
* @param node the node of the permission to check
|
||||||
|
* @param permissionChecker permission checking function
|
||||||
|
* @param sender the sender to inform of the result
|
||||||
|
* @param <P> the player type
|
||||||
|
*/
|
||||||
|
private static <P extends OfflinePlayer> void performPermissionCheck(
|
||||||
|
P player, String node, BiFunction<P, PermissionNode, Boolean> permissionChecker, CommandSender sender) {
|
||||||
|
|
||||||
|
PermissionNode permNode = getPermissionNode(sender, node);
|
||||||
|
if (permissionChecker.apply(player, permNode)) {
|
||||||
|
sender.sendMessage(ChatColor.DARK_GREEN + "Success: player '" + player.getName()
|
||||||
|
+ "' has permission '" + node + "'");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(ChatColor.DARK_RED + "Check failed: player '" + player.getName()
|
||||||
|
+ "' does NOT have permission '" + node + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on the given permission node (String), tries to find the according AuthMe {@link PermissionNode}
|
||||||
|
* instance, or creates a new one if not available.
|
||||||
|
*
|
||||||
|
* @param sender the sender (used to inform him if no AuthMe PermissionNode can be matched)
|
||||||
|
* @param node the node to search for
|
||||||
|
* @return the node as {@link PermissionNode} object
|
||||||
|
*/
|
||||||
|
private static PermissionNode getPermissionNode(CommandSender sender, String node) {
|
||||||
|
Optional<? extends PermissionNode> permNode = PERMISSION_NODE_CLASSES.stream()
|
||||||
|
.map(Class::getEnumConstants)
|
||||||
|
.flatMap(Arrays::stream)
|
||||||
|
.filter(perm -> perm.getNode().equals(node))
|
||||||
|
.findFirst();
|
||||||
|
if (permNode.isPresent()) {
|
||||||
|
return permNode.get();
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Did not detect AuthMe permission; using default permission = DENIED");
|
||||||
|
return createPermNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PermissionNode createPermNode(String node) {
|
||||||
|
return new PermissionNode() {
|
||||||
|
@Override
|
||||||
|
public String getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DefaultPermission getDefaultPermission() {
|
||||||
|
return DefaultPermission.NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
package fr.xephi.authme.command.executable.authme.debug;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
|
import fr.xephi.authme.data.limbo.persistence.LimboPersistence;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation;
|
||||||
|
import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.applyToLimboPlayersMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the data stored in LimboPlayers and the equivalent properties on online players.
|
||||||
|
*/
|
||||||
|
class LimboPlayerViewer implements DebugSection {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboService limboService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboPersistence limboPersistence;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "limbo";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "View LimboPlayers and player's \"limbo stats\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
sender.sendMessage("/authme debug limbo <player>: show a player's limbo info");
|
||||||
|
sender.sendMessage("Available limbo records: " + applyToLimboPlayersMap(limboService, Map::keySet));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LimboPlayer memoryLimbo = limboService.getLimboPlayer(arguments.get(0));
|
||||||
|
Player player = bukkitService.getPlayerExact(arguments.get(0));
|
||||||
|
LimboPlayer diskLimbo = player != null ? limboPersistence.getLimboPlayer(player) : null;
|
||||||
|
if (memoryLimbo == null && player == null) {
|
||||||
|
sender.sendMessage("No limbo info and no player online with name '" + arguments.get(0) + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "Showing disk limbo / limbo / player info for '" + arguments.get(0) + "'");
|
||||||
|
new InfoDisplayer(sender, diskLimbo, memoryLimbo, player)
|
||||||
|
.sendEntry("Is op", LimboPlayer::isOperator, Player::isOp)
|
||||||
|
.sendEntry("Walk speed", LimboPlayer::getWalkSpeed, Player::getWalkSpeed)
|
||||||
|
.sendEntry("Can fly", LimboPlayer::isCanFly, Player::getAllowFlight)
|
||||||
|
.sendEntry("Fly speed", LimboPlayer::getFlySpeed, Player::getFlySpeed)
|
||||||
|
.sendEntry("Location", l -> formatLocation(l.getLocation()), p -> formatLocation(p.getLocation()))
|
||||||
|
.sendEntry("Group", LimboPlayer::getGroup, p -> "");
|
||||||
|
sender.sendMessage("Note: group is not shown for Player. Use /authme debug groups");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the info for the given LimboPlayer and Player to the provided CommandSender.
|
||||||
|
*/
|
||||||
|
private static final class InfoDisplayer {
|
||||||
|
private final CommandSender sender;
|
||||||
|
private final Optional<LimboPlayer> diskLimbo;
|
||||||
|
private final Optional<LimboPlayer> memoryLimbo;
|
||||||
|
private final Optional<Player> player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param sender command sender to send the information to
|
||||||
|
* @param memoryLimbo the limbo player to get data from
|
||||||
|
* @param player the player to get data from
|
||||||
|
*/
|
||||||
|
InfoDisplayer(CommandSender sender, LimboPlayer diskLimbo, LimboPlayer memoryLimbo, Player player) {
|
||||||
|
this.sender = sender;
|
||||||
|
this.diskLimbo = Optional.ofNullable(diskLimbo);
|
||||||
|
this.memoryLimbo = Optional.ofNullable(memoryLimbo);
|
||||||
|
this.player = Optional.ofNullable(player);
|
||||||
|
|
||||||
|
if (memoryLimbo == null) {
|
||||||
|
sender.sendMessage("Note: no Limbo information available");
|
||||||
|
}
|
||||||
|
if (player == null) {
|
||||||
|
sender.sendMessage("Note: player is not online");
|
||||||
|
} else if (diskLimbo == null) {
|
||||||
|
sender.sendMessage("Note: no Limbo on disk available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a piece of information to the command sender.
|
||||||
|
*
|
||||||
|
* @param title the designation of the piece of information
|
||||||
|
* @param limboGetter getter for data retrieval on the LimboPlayer
|
||||||
|
* @param playerGetter getter for data retrieval on Player
|
||||||
|
* @param <T> the data type
|
||||||
|
* @return this instance (for chaining)
|
||||||
|
*/
|
||||||
|
<T> InfoDisplayer sendEntry(String title,
|
||||||
|
Function<LimboPlayer, T> limboGetter,
|
||||||
|
Function<Player, T> playerGetter) {
|
||||||
|
sender.sendMessage(
|
||||||
|
title + ": "
|
||||||
|
+ getData(diskLimbo, limboGetter)
|
||||||
|
+ " / "
|
||||||
|
+ getData(memoryLimbo, limboGetter)
|
||||||
|
+ " / "
|
||||||
|
+ getData(player, playerGetter));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static <E, T> String getData(Optional<E> entity, Function<E, T> getter) {
|
||||||
|
return entity.map(getter).map(String::valueOf).orElse(" -- ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
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.security.crypts.HashedPassword;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.command.executable.authme.debug.DebugSectionUtils.formatLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to view the data of a PlayerAuth in the database.
|
||||||
|
*/
|
||||||
|
class PlayerAuthViewer implements DebugSection {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "db";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "View player's data in the database";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
sender.sendMessage("Enter player name to view his data in the database.");
|
||||||
|
sender.sendMessage("Example: /authme debug db Bobby");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerAuth auth = dataSource.getAuth(arguments.get(0));
|
||||||
|
if (auth == null) {
|
||||||
|
sender.sendMessage("No record exists for '" + arguments.get(0) + "'");
|
||||||
|
} else {
|
||||||
|
displayAuthToSender(auth, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the PlayerAuth information to the given sender.
|
||||||
|
*
|
||||||
|
* @param auth the PlayerAuth to display
|
||||||
|
* @param sender the sender to send the messages to
|
||||||
|
*/
|
||||||
|
private void displayAuthToSender(PlayerAuth auth, CommandSender sender) {
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "[AuthMe] Player " + auth.getNickname() + " / " + auth.getRealName());
|
||||||
|
sender.sendMessage("Email: " + auth.getEmail() + ". IP: " + auth.getIp() + ". Group: " + auth.getGroupId());
|
||||||
|
sender.sendMessage("Quit location: "
|
||||||
|
+ formatLocation(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld()));
|
||||||
|
sender.sendMessage("Last login: " + formatLastLogin(auth));
|
||||||
|
|
||||||
|
HashedPassword hashedPass = auth.getPassword();
|
||||||
|
sender.sendMessage("Hash / salt (partial): '" + safeSubstring(hashedPass.getHash(), 6)
|
||||||
|
+ "' / '" + safeSubstring(hashedPass.getSalt(), 4) + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fail-safe substring method. Guarantees not to show the entire String.
|
||||||
|
*
|
||||||
|
* @param str the string to transform
|
||||||
|
* @param length number of characters to show from the start of the String
|
||||||
|
* @return the first <code>length</code> characters of the string, or half of the string if it is shorter,
|
||||||
|
* or empty string if the string is null or empty
|
||||||
|
*/
|
||||||
|
private static String safeSubstring(String str, int length) {
|
||||||
|
if (StringUtils.isEmpty(str)) {
|
||||||
|
return "";
|
||||||
|
} else if (str.length() < length) {
|
||||||
|
return str.substring(0, str.length() / 2) + "...";
|
||||||
|
} else {
|
||||||
|
return str.substring(0, length) + "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the last login date from the given PlayerAuth.
|
||||||
|
*
|
||||||
|
* @param auth the auth object
|
||||||
|
* @return the last login as human readable date
|
||||||
|
*/
|
||||||
|
private static String formatLastLogin(PlayerAuth auth) {
|
||||||
|
long lastLogin = auth.getLastLogin();
|
||||||
|
if (lastLogin == 0) {
|
||||||
|
return "Never (0)";
|
||||||
|
} else {
|
||||||
|
LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastLogin), ZoneId.systemDefault());
|
||||||
|
return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -41,8 +41,8 @@ class TestEmailSender implements DebugSection {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, List<String> arguments) {
|
public void execute(CommandSender sender, List<String> arguments) {
|
||||||
if (!sendMailSSL.hasAllInformation()) {
|
if (!sendMailSSL.hasAllInformation()) {
|
||||||
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml " +
|
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml "
|
||||||
"for sending emails. Please check your config.yml");
|
+ "for sending emails. Please check your config.yml");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,8 @@ class TestEmailSender implements DebugSection {
|
|||||||
}
|
}
|
||||||
String email = auth.getEmail();
|
String email = auth.getEmail();
|
||||||
if (email == null || "your@email.com".equals(email)) {
|
if (email == null || "your@email.com".equals(email)) {
|
||||||
sender.sendMessage(ChatColor.RED + "No email set for your account! Please use /authme debug mail <email>");
|
sender.sendMessage(ChatColor.RED + "No email set for your account!"
|
||||||
|
+ " Please use /authme debug mail <email>");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return email;
|
return email;
|
||||||
|
|||||||
@ -3,8 +3,7 @@ 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.LimboService;
|
||||||
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;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -24,7 +23,7 @@ public class CaptchaCommand extends PlayerCommand {
|
|||||||
private CommonService commonService;
|
private CommonService commonService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
@ -44,7 +43,7 @@ public class CaptchaCommand extends PlayerCommand {
|
|||||||
if (isCorrectCode) {
|
if (isCorrectCode) {
|
||||||
commonService.send(player, MessageKey.CAPTCHA_SUCCESS);
|
commonService.send(player, MessageKey.CAPTCHA_SUCCESS);
|
||||||
commonService.send(player, MessageKey.LOGIN_MESSAGE);
|
commonService.send(player, MessageKey.LOGIN_MESSAGE);
|
||||||
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(false);
|
limboService.unmuteMessageTask(player);
|
||||||
} else {
|
} else {
|
||||||
String newCode = captchaManager.generateCode(player.getName());
|
String newCode = captchaManager.generateCode(player.getName());
|
||||||
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
||||||
|
|||||||
@ -24,7 +24,7 @@ public class ShowEmailCommand extends PlayerCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
PlayerAuth auth = playerCache.getAuth(player.getName());
|
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||||
if (auth.getEmail() != null && !"your@email.com".equalsIgnoreCase(auth.getEmail())) {
|
if (auth != null && auth.getEmail() != null && !"your@email.com".equalsIgnoreCase(auth.getEmail())) {
|
||||||
commonService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail());
|
commonService.send(player, MessageKey.EMAIL_SHOW, auth.getEmail());
|
||||||
} else {
|
} else {
|
||||||
commonService.send(player, MessageKey.SHOW_NO_EMAIL);
|
commonService.send(player, MessageKey.SHOW_NO_EMAIL);
|
||||||
|
|||||||
@ -7,7 +7,10 @@ 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;
|
||||||
import fr.xephi.authme.process.register.RegistrationType;
|
import fr.xephi.authme.process.register.RegistrationType;
|
||||||
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
|
import fr.xephi.authme.process.register.executors.EmailRegisterParams;
|
||||||
|
import fr.xephi.authme.process.register.executors.PasswordRegisterParams;
|
||||||
|
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
||||||
|
import fr.xephi.authme.process.register.executors.TwoFactorRegisterParams;
|
||||||
import fr.xephi.authme.security.HashAlgorithm;
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.service.ValidationService;
|
import fr.xephi.authme.service.ValidationService;
|
||||||
@ -42,15 +45,12 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private RegistrationExecutorProvider registrationExecutorProvider;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
||||||
//for two factor auth we don't need to check the usage
|
//for two factor auth we don't need to check the usage
|
||||||
management.performRegister(player,
|
management.performRegister(RegistrationMethod.TWO_FACTOR_REGISTRATION,
|
||||||
registrationExecutorProvider.getTwoFactorRegisterExecutor(player));
|
TwoFactorRegisterParams.of(player));
|
||||||
return;
|
return;
|
||||||
} else if (arguments.size() < 1) {
|
} else if (arguments.size() < 1) {
|
||||||
commonService.send(player, MessageKey.USAGE_REGISTER);
|
commonService.send(player, MessageKey.USAGE_REGISTER);
|
||||||
@ -82,8 +82,8 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
final String password = arguments.get(0);
|
final String password = arguments.get(0);
|
||||||
final String email = getEmailIfAvailable(arguments);
|
final String email = getEmailIfAvailable(arguments);
|
||||||
|
|
||||||
management.performRegister(
|
management.performRegister(RegistrationMethod.PASSWORD_REGISTRATION,
|
||||||
player, registrationExecutorProvider.getPasswordRegisterExecutor(player, password, email));
|
PasswordRegisterParams.of(player, password, email));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,8 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
if (!validationService.validateEmail(email)) {
|
if (!validationService.validateEmail(email)) {
|
||||||
commonService.send(player, MessageKey.INVALID_EMAIL);
|
commonService.send(player, MessageKey.INVALID_EMAIL);
|
||||||
} else if (isSecondArgValidForEmailRegistration(player, arguments)) {
|
} else if (isSecondArgValidForEmailRegistration(player, arguments)) {
|
||||||
management.performRegister(player, registrationExecutorProvider.getEmailRegisterExecutor(player, email));
|
management.performRegister(RegistrationMethod.EMAIL_REGISTRATION,
|
||||||
|
EmailRegisterParams.of(player, email));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible types to restore the "allow flight" property
|
||||||
|
* from LimboPlayer to Bukkit Player.
|
||||||
|
*/
|
||||||
|
public enum AllowFlightRestoreType {
|
||||||
|
|
||||||
|
/** Set value from LimboPlayer to Player. */
|
||||||
|
RESTORE(LimboPlayer::isCanFly),
|
||||||
|
|
||||||
|
/** Always set flight enabled to true. */
|
||||||
|
ENABLE(l -> true),
|
||||||
|
|
||||||
|
/** Always set flight enabled to false. */
|
||||||
|
DISABLE(l -> false);
|
||||||
|
|
||||||
|
private final Function<LimboPlayer, Boolean> valueGetter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param valueGetter function with which the value to set on the player can be retrieved
|
||||||
|
*/
|
||||||
|
AllowFlightRestoreType(Function<LimboPlayer, Boolean> valueGetter) {
|
||||||
|
this.valueGetter = valueGetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the "allow flight" property from the LimboPlayer to the Player.
|
||||||
|
* This method behaves differently for each restoration type.
|
||||||
|
*
|
||||||
|
* @param player the player to modify
|
||||||
|
* @param limbo the limbo player to read from
|
||||||
|
*/
|
||||||
|
public void restoreAllowFlight(Player player, LimboPlayer limbo) {
|
||||||
|
player.setAllowFlight(valueGetter.apply(limbo));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,151 +0,0 @@
|
|||||||
package fr.xephi.authme.data.limbo;
|
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages all {@link LimboPlayer} instances.
|
|
||||||
*/
|
|
||||||
public class LimboCache {
|
|
||||||
|
|
||||||
private final Map<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private LimboPlayerStorage limboPlayerStorage;
|
|
||||||
private PermissionsManager permissionsManager;
|
|
||||||
private SpawnLoader spawnLoader;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader, LimboPlayerStorage limboPlayerStorage) {
|
|
||||||
this.permissionsManager = permissionsManager;
|
|
||||||
this.spawnLoader = spawnLoader;
|
|
||||||
this.limboPlayerStorage = limboPlayerStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load player data if exist, otherwise current player's data will be stored.
|
|
||||||
*
|
|
||||||
* @param player Player instance to add.
|
|
||||||
*/
|
|
||||||
public void addPlayerData(Player player) {
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
|
||||||
boolean operator = player.isOp();
|
|
||||||
boolean flyEnabled = player.getAllowFlight();
|
|
||||||
float walkSpeed = player.getWalkSpeed();
|
|
||||||
float flySpeed = player.getFlySpeed();
|
|
||||||
String playerGroup = "";
|
|
||||||
if (permissionsManager.hasGroupSupport()) {
|
|
||||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
|
||||||
}
|
|
||||||
ConsoleLogger.debug("Player `{0}` has primary group `{1}`", player.getName(), playerGroup);
|
|
||||||
|
|
||||||
if (limboPlayerStorage.hasData(player)) {
|
|
||||||
LimboPlayer cache = limboPlayerStorage.readData(player);
|
|
||||||
if (cache != null) {
|
|
||||||
location = cache.getLocation();
|
|
||||||
playerGroup = cache.getGroup();
|
|
||||||
operator = cache.isOperator();
|
|
||||||
flyEnabled = cache.isCanFly();
|
|
||||||
walkSpeed = cache.getWalkSpeed();
|
|
||||||
flySpeed = cache.getFlySpeed();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
limboPlayerStorage.saveData(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.put(name, new LimboPlayer(location, operator, playerGroup, flyEnabled, walkSpeed, flySpeed));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore player's data to player if exist.
|
|
||||||
*
|
|
||||||
* @param player Player instance to restore
|
|
||||||
*/
|
|
||||||
public void restoreData(Player player) {
|
|
||||||
String lowerName = player.getName().toLowerCase();
|
|
||||||
if (cache.containsKey(lowerName)) {
|
|
||||||
LimboPlayer data = cache.get(lowerName);
|
|
||||||
player.setOp(data.isOperator());
|
|
||||||
player.setAllowFlight(data.isCanFly());
|
|
||||||
float walkSpeed = data.getWalkSpeed();
|
|
||||||
float flySpeed = data.getFlySpeed();
|
|
||||||
// Reset the speed value if it was 0
|
|
||||||
if (walkSpeed < 0.01f) {
|
|
||||||
walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
|
||||||
}
|
|
||||||
if (flySpeed < 0.01f) {
|
|
||||||
flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
|
||||||
}
|
|
||||||
player.setWalkSpeed(walkSpeed);
|
|
||||||
player.setFlySpeed(flySpeed);
|
|
||||||
data.clearTasks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove PlayerData from cache and disk.
|
|
||||||
*
|
|
||||||
* @param player Player player to remove.
|
|
||||||
*/
|
|
||||||
public void deletePlayerData(Player player) {
|
|
||||||
removeFromCache(player);
|
|
||||||
limboPlayerStorage.removeData(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove PlayerData from cache.
|
|
||||||
*
|
|
||||||
* @param player player to remove.
|
|
||||||
*/
|
|
||||||
public void removeFromCache(Player player) {
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
LimboPlayer cachedPlayer = cache.remove(name);
|
|
||||||
if (cachedPlayer != null) {
|
|
||||||
cachedPlayer.clearTasks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method getPlayerData.
|
|
||||||
*
|
|
||||||
* @param name String
|
|
||||||
*
|
|
||||||
* @return PlayerData
|
|
||||||
*/
|
|
||||||
public LimboPlayer getPlayerData(String name) {
|
|
||||||
checkNotNull(name);
|
|
||||||
return cache.get(name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method hasPlayerData.
|
|
||||||
*
|
|
||||||
* @param name String
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public boolean hasPlayerData(String name) {
|
|
||||||
checkNotNull(name);
|
|
||||||
return cache.containsKey(name.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method updatePlayerData.
|
|
||||||
*
|
|
||||||
* @param player Player
|
|
||||||
*/
|
|
||||||
public void updatePlayerData(Player player) {
|
|
||||||
checkNotNull(player);
|
|
||||||
removeFromCache(player);
|
|
||||||
addPlayerData(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -118,13 +118,7 @@ public class LimboPlayer {
|
|||||||
* Clears all tasks associated to the player.
|
* Clears all tasks associated to the player.
|
||||||
*/
|
*/
|
||||||
public void clearTasks() {
|
public void clearTasks() {
|
||||||
if (messageTask != null) {
|
setMessageTask(null);
|
||||||
messageTask.cancel();
|
setTimeoutTask(null);
|
||||||
}
|
|
||||||
messageTask = null;
|
|
||||||
if (timeoutTask != null) {
|
|
||||||
timeoutTask.cancel();
|
|
||||||
}
|
|
||||||
timeoutTask = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,213 +0,0 @@
|
|||||||
package fr.xephi.authme.data.limbo;
|
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
|
||||||
import fr.xephi.authme.util.FileUtils;
|
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to store player's data (OP, flying, speed, position) to disk.
|
|
||||||
*/
|
|
||||||
public class LimboPlayerStorage {
|
|
||||||
|
|
||||||
private final Gson gson;
|
|
||||||
private final File cacheDir;
|
|
||||||
private PermissionsManager permissionsManager;
|
|
||||||
private SpawnLoader spawnLoader;
|
|
||||||
private BukkitService bukkitService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
LimboPlayerStorage(@DataFolder File dataFolder, PermissionsManager permsMan,
|
|
||||||
SpawnLoader spawnLoader, BukkitService bukkitService) {
|
|
||||||
this.permissionsManager = permsMan;
|
|
||||||
this.spawnLoader = spawnLoader;
|
|
||||||
this.bukkitService = bukkitService;
|
|
||||||
|
|
||||||
cacheDir = new File(dataFolder, "playerdata");
|
|
||||||
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
|
|
||||||
ConsoleLogger.warning("Failed to create userdata directory.");
|
|
||||||
}
|
|
||||||
gson = new GsonBuilder()
|
|
||||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
|
||||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer())
|
|
||||||
.setPrettyPrinting()
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read and construct new PlayerData from existing player data.
|
|
||||||
*
|
|
||||||
* @param player player to read
|
|
||||||
*
|
|
||||||
* @return PlayerData object if the data is exist, null otherwise.
|
|
||||||
*/
|
|
||||||
public LimboPlayer readData(Player player) {
|
|
||||||
String id = PlayerUtils.getUUIDorName(player);
|
|
||||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
|
||||||
if (!file.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String str = Files.toString(file, StandardCharsets.UTF_8);
|
|
||||||
return gson.fromJson(str, LimboPlayer.class);
|
|
||||||
} catch (IOException e) {
|
|
||||||
ConsoleLogger.logException("Could not read player data on disk for '" + player.getName() + "'", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save player data (OP, flying, location, etc) to disk.
|
|
||||||
*
|
|
||||||
* @param player player to save
|
|
||||||
*/
|
|
||||||
public void saveData(Player player) {
|
|
||||||
String id = PlayerUtils.getUUIDorName(player);
|
|
||||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
|
||||||
String group = "";
|
|
||||||
if (permissionsManager.hasGroupSupport()) {
|
|
||||||
group = permissionsManager.getPrimaryGroup(player);
|
|
||||||
}
|
|
||||||
boolean operator = player.isOp();
|
|
||||||
boolean canFly = player.getAllowFlight();
|
|
||||||
float walkSpeed = player.getWalkSpeed();
|
|
||||||
float flySpeed = player.getFlySpeed();
|
|
||||||
LimboPlayer limboPlayer = new LimboPlayer(location, operator, group, canFly, walkSpeed, flySpeed);
|
|
||||||
try {
|
|
||||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
|
||||||
Files.createParentDirs(file);
|
|
||||||
Files.touch(file);
|
|
||||||
Files.write(gson.toJson(limboPlayer), file, StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException e) {
|
|
||||||
ConsoleLogger.logException("Failed to write " + player.getName() + " data.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove player data, this will delete
|
|
||||||
* "playerdata/<uuid or name>/" folder from disk.
|
|
||||||
*
|
|
||||||
* @param player player to remove
|
|
||||||
*/
|
|
||||||
public void removeData(Player player) {
|
|
||||||
String id = PlayerUtils.getUUIDorName(player);
|
|
||||||
File file = new File(cacheDir, id);
|
|
||||||
if (file.exists()) {
|
|
||||||
FileUtils.purgeDirectory(file);
|
|
||||||
if (!file.delete()) {
|
|
||||||
ConsoleLogger.warning("Failed to remove " + player.getName() + " cache.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use to check is player data is exist.
|
|
||||||
*
|
|
||||||
* @param player player to check
|
|
||||||
*
|
|
||||||
* @return true if data exist, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean hasData(Player player) {
|
|
||||||
String id = PlayerUtils.getUUIDorName(player);
|
|
||||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
|
||||||
return file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LimboPlayerDeserializer implements JsonDeserializer<LimboPlayer> {
|
|
||||||
@Override
|
|
||||||
public LimboPlayer deserialize(JsonElement jsonElement, Type type,
|
|
||||||
JsonDeserializationContext context) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
if (jsonObject == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Location loc = null;
|
|
||||||
String group = "";
|
|
||||||
boolean operator = false;
|
|
||||||
boolean canFly = false;
|
|
||||||
float walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
|
||||||
float flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
|
||||||
|
|
||||||
JsonElement e;
|
|
||||||
if ((e = jsonObject.getAsJsonObject("location")) != null) {
|
|
||||||
JsonObject obj = e.getAsJsonObject();
|
|
||||||
World world = bukkitService.getWorld(obj.get("world").getAsString());
|
|
||||||
if (world != null) {
|
|
||||||
double x = obj.get("x").getAsDouble();
|
|
||||||
double y = obj.get("y").getAsDouble();
|
|
||||||
double z = obj.get("z").getAsDouble();
|
|
||||||
float yaw = obj.get("yaw").getAsFloat();
|
|
||||||
float pitch = obj.get("pitch").getAsFloat();
|
|
||||||
loc = new Location(world, x, y, z, yaw, pitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("group")) != null) {
|
|
||||||
group = e.getAsString();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("operator")) != null) {
|
|
||||||
operator = e.getAsBoolean();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("can-fly")) != null) {
|
|
||||||
canFly = e.getAsBoolean();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("walk-speed")) != null) {
|
|
||||||
walkSpeed = e.getAsFloat();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("fly-speed")) != null) {
|
|
||||||
flySpeed = e.getAsFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LimboPlayer(loc, operator, group, canFly, walkSpeed, flySpeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LimboPlayerSerializer implements JsonSerializer<LimboPlayer> {
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(LimboPlayer limboPlayer, Type type,
|
|
||||||
JsonSerializationContext context) {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
obj.addProperty("group", limboPlayer.getGroup());
|
|
||||||
|
|
||||||
Location loc = limboPlayer.getLocation();
|
|
||||||
JsonObject obj2 = new JsonObject();
|
|
||||||
obj2.addProperty("world", loc.getWorld().getName());
|
|
||||||
obj2.addProperty("x", loc.getX());
|
|
||||||
obj2.addProperty("y", loc.getY());
|
|
||||||
obj2.addProperty("z", loc.getZ());
|
|
||||||
obj2.addProperty("yaw", loc.getYaw());
|
|
||||||
obj2.addProperty("pitch", loc.getPitch());
|
|
||||||
obj.add("location", obj2);
|
|
||||||
|
|
||||||
obj.addProperty("operator", limboPlayer.isOperator());
|
|
||||||
obj.addProperty("can-fly", limboPlayer.isCanFly());
|
|
||||||
obj.addProperty("walk-speed", limboPlayer.getWalkSpeed());
|
|
||||||
obj.addProperty("fly-speed", limboPlayer.getFlySpeed());
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.message.Messages;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
|
import fr.xephi.authme.task.MessageTask;
|
||||||
|
import fr.xephi.authme.task.TimeoutTask;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers tasks associated with a LimboPlayer.
|
||||||
|
*/
|
||||||
|
class LimboPlayerTaskManager {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Messages messages;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Settings settings;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
|
LimboPlayerTaskManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a {@link MessageTask} for the given player name.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @param limbo the associated limbo player of the player
|
||||||
|
* @param isRegistered whether the player is registered or not
|
||||||
|
* (false shows "please register", true shows "please log in")
|
||||||
|
*/
|
||||||
|
void registerMessageTask(Player player, LimboPlayer limbo, boolean isRegistered) {
|
||||||
|
int interval = settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL);
|
||||||
|
MessageKey key = getMessageKey(isRegistered);
|
||||||
|
if (interval > 0) {
|
||||||
|
MessageTask messageTask = new MessageTask(player, messages.retrieve(key));
|
||||||
|
bukkitService.runTaskTimer(messageTask, 2 * TICKS_PER_SECOND, interval * TICKS_PER_SECOND);
|
||||||
|
limbo.setMessageTask(messageTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a {@link TimeoutTask} for the given player according to the configuration.
|
||||||
|
*
|
||||||
|
* @param player the player to register a timeout task for
|
||||||
|
* @param limbo the associated limbo player
|
||||||
|
*/
|
||||||
|
void registerTimeoutTask(Player player, LimboPlayer limbo) {
|
||||||
|
final int timeout = settings.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||||
|
if (timeout > 0) {
|
||||||
|
String message = messages.retrieveSingle(MessageKey.LOGIN_TIMEOUT_ERROR);
|
||||||
|
BukkitTask task = bukkitService.runTaskLater(new TimeoutTask(player, message, playerCache), timeout);
|
||||||
|
limbo.setTimeoutTask(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null-safe method to set the muted flag on a message task.
|
||||||
|
*
|
||||||
|
* @param task the task to modify (or null)
|
||||||
|
* @param isMuted the value to set if task is not null
|
||||||
|
*/
|
||||||
|
static void setMuted(MessageTask task, boolean isMuted) {
|
||||||
|
if (task != null) {
|
||||||
|
task.setMuted(isMuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the appropriate message key according to the registration status and settings.
|
||||||
|
*
|
||||||
|
* @param isRegistered whether or not the username is registered
|
||||||
|
* @return the message key to display to the user
|
||||||
|
*/
|
||||||
|
private static MessageKey getMessageKey(boolean isRegistered) {
|
||||||
|
if (isRegistered) {
|
||||||
|
return MessageKey.LOGIN_MESSAGE;
|
||||||
|
} else {
|
||||||
|
return MessageKey.REGISTER_MESSAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
170
src/main/java/fr/xephi/authme/data/limbo/LimboService.java
Normal file
170
src/main/java/fr/xephi/authme/data/limbo/LimboService.java
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.persistence.LimboPersistence;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_ALLOW_FLIGHT;
|
||||||
|
import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_FLY_SPEED;
|
||||||
|
import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_WALK_SPEED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for managing players that are in "limbo," a temporary state players are
|
||||||
|
* put in which have joined but not yet logged in yet.
|
||||||
|
*/
|
||||||
|
public class LimboService {
|
||||||
|
|
||||||
|
private final Map<String, LimboPlayer> entries = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Settings settings;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboPlayerTaskManager taskManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboServiceHelper helper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboPersistence persistence;
|
||||||
|
|
||||||
|
LimboService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a LimboPlayer for the given player and revokes all "limbo data" from the player.
|
||||||
|
*
|
||||||
|
* @param player the player to process
|
||||||
|
* @param isRegistered whether or not the player is registered
|
||||||
|
*/
|
||||||
|
public void createLimboPlayer(Player player, boolean isRegistered) {
|
||||||
|
final String name = player.getName().toLowerCase();
|
||||||
|
|
||||||
|
LimboPlayer limboFromDisk = persistence.getLimboPlayer(player);
|
||||||
|
if (limboFromDisk != null) {
|
||||||
|
ConsoleLogger.debug("LimboPlayer for `{0}` already exists on disk", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LimboPlayer existingLimbo = entries.remove(name);
|
||||||
|
if (existingLimbo != null) {
|
||||||
|
existingLimbo.clearTasks();
|
||||||
|
ConsoleLogger.debug("LimboPlayer for `{0}` already present in memory", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LimboPlayer limboPlayer = helper.merge(existingLimbo, limboFromDisk);
|
||||||
|
limboPlayer = helper.merge(helper.createLimboPlayer(player, isRegistered), limboPlayer);
|
||||||
|
|
||||||
|
taskManager.registerMessageTask(player, limboPlayer, isRegistered);
|
||||||
|
taskManager.registerTimeoutTask(player, limboPlayer);
|
||||||
|
helper.revokeLimboStates(player);
|
||||||
|
entries.put(name, limboPlayer);
|
||||||
|
persistence.saveLimboPlayer(player, limboPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the limbo player for the given name, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param name the name to retrieve the data for
|
||||||
|
* @return the associated limbo player, or null if none available
|
||||||
|
*/
|
||||||
|
public LimboPlayer getLimboPlayer(String name) {
|
||||||
|
return entries.get(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether there is a limbo player for the given name.
|
||||||
|
*
|
||||||
|
* @param name the name to check
|
||||||
|
* @return true if present, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasLimboPlayer(String name) {
|
||||||
|
return entries.containsKey(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the limbo data and subsequently deletes the entry.
|
||||||
|
* <p>
|
||||||
|
* Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and
|
||||||
|
* changing the permission group is handled by {@link fr.xephi.authme.permission.AuthGroupHandler}.
|
||||||
|
*
|
||||||
|
* @param player the player whose data should be restored
|
||||||
|
*/
|
||||||
|
public void restoreData(Player player) {
|
||||||
|
String lowerName = player.getName().toLowerCase();
|
||||||
|
LimboPlayer limbo = entries.remove(lowerName);
|
||||||
|
|
||||||
|
if (limbo == null) {
|
||||||
|
ConsoleLogger.debug("No LimboPlayer found for `{0}` - cannot restore", lowerName);
|
||||||
|
} else {
|
||||||
|
player.setOp(limbo.isOperator());
|
||||||
|
settings.getProperty(RESTORE_ALLOW_FLIGHT).restoreAllowFlight(player, limbo);
|
||||||
|
settings.getProperty(RESTORE_FLY_SPEED).restoreFlySpeed(player, limbo);
|
||||||
|
settings.getProperty(RESTORE_WALK_SPEED).restoreWalkSpeed(player, limbo);
|
||||||
|
limbo.clearTasks();
|
||||||
|
ConsoleLogger.debug("Restored LimboPlayer stats for `{0}`", lowerName);
|
||||||
|
persistence.removeLimboPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new tasks for the given player and cancels the old ones for a newly registered player.
|
||||||
|
* This resets his time to log in (TimeoutTask) and updates the message he is shown (MessageTask).
|
||||||
|
*
|
||||||
|
* @param player the player to reset the tasks for
|
||||||
|
*/
|
||||||
|
public void replaceTasksAfterRegistration(Player player) {
|
||||||
|
getLimboOrLogError(player, "reset tasks")
|
||||||
|
.ifPresent(limbo -> {
|
||||||
|
taskManager.registerTimeoutTask(player, limbo);
|
||||||
|
taskManager.registerMessageTask(player, limbo, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the message task associated with the player's LimboPlayer.
|
||||||
|
*
|
||||||
|
* @param player the player to set a new message task for
|
||||||
|
* @param isRegistered whether or not the player is registered
|
||||||
|
*/
|
||||||
|
public void resetMessageTask(Player player, boolean isRegistered) {
|
||||||
|
getLimboOrLogError(player, "reset message task")
|
||||||
|
.ifPresent(limbo -> taskManager.registerMessageTask(player, limbo, isRegistered));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player the player whose message task should be muted
|
||||||
|
*/
|
||||||
|
public void muteMessageTask(Player player) {
|
||||||
|
getLimboOrLogError(player, "mute message task")
|
||||||
|
.ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player the player whose message task should be unmuted
|
||||||
|
*/
|
||||||
|
public void unmuteMessageTask(Player player) {
|
||||||
|
getLimboOrLogError(player, "unmute message task")
|
||||||
|
.ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the limbo player for the given player or logs an error.
|
||||||
|
*
|
||||||
|
* @param player the player to retrieve the limbo player for
|
||||||
|
* @param context the action for which the limbo player is being retrieved (for logging)
|
||||||
|
* @return Optional with the limbo player
|
||||||
|
*/
|
||||||
|
private Optional<LimboPlayer> getLimboOrLogError(Player player, String context) {
|
||||||
|
LimboPlayer limbo = entries.get(player.getName().toLowerCase());
|
||||||
|
if (limbo == null) {
|
||||||
|
ConsoleLogger.debug("No LimboPlayer found for `{0}`. Action: {1}", player.getName(), context);
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(limbo);
|
||||||
|
}
|
||||||
|
}
|
||||||
107
src/main/java/fr/xephi/authme/data/limbo/LimboServiceHelper.java
Normal file
107
src/main/java/fr/xephi/authme/data/limbo/LimboServiceHelper.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for the LimboService.
|
||||||
|
*/
|
||||||
|
class LimboServiceHelper {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpawnLoader spawnLoader;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Settings settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a LimboPlayer with the given player's details.
|
||||||
|
*
|
||||||
|
* @param player the player to process
|
||||||
|
* @param isRegistered whether the player is registered
|
||||||
|
* @return limbo player with the player's data
|
||||||
|
*/
|
||||||
|
LimboPlayer createLimboPlayer(Player player, boolean isRegistered) {
|
||||||
|
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||||
|
// For safety reasons an unregistered player should not have OP status after registration
|
||||||
|
boolean isOperator = isRegistered && player.isOp();
|
||||||
|
boolean flyEnabled = player.getAllowFlight();
|
||||||
|
float walkSpeed = player.getWalkSpeed();
|
||||||
|
float flySpeed = player.getFlySpeed();
|
||||||
|
String playerGroup = permissionsManager.hasGroupSupport()
|
||||||
|
? permissionsManager.getPrimaryGroup(player) : "";
|
||||||
|
ConsoleLogger.debug("Player `{0}` has primary group `{1}`", player.getName(), playerGroup);
|
||||||
|
|
||||||
|
return new LimboPlayer(location, isOperator, playerGroup, flyEnabled, walkSpeed, flySpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the data that is saved in a LimboPlayer from the player.
|
||||||
|
* <p>
|
||||||
|
* Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and
|
||||||
|
* changing the permission group is handled by {@link fr.xephi.authme.permission.AuthGroupHandler}.
|
||||||
|
*
|
||||||
|
* @param player the player to set defaults to
|
||||||
|
*/
|
||||||
|
void revokeLimboStates(Player player) {
|
||||||
|
player.setOp(false);
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
|
||||||
|
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
|
||||||
|
&& settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
||||||
|
player.setFlySpeed(0.0f);
|
||||||
|
player.setWalkSpeed(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges two existing LimboPlayer instances of a player. Merging is done the following way:
|
||||||
|
* <ul>
|
||||||
|
* <li><code>isOperator, allowFlight</code>: true if either limbo has true</li>
|
||||||
|
* <li><code>flySpeed, walkSpeed</code>: maximum value of either limbo player</li>
|
||||||
|
* <li><code>group, location</code>: from old limbo if not empty/null, otherwise from new limbo</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param newLimbo the new limbo player
|
||||||
|
* @param oldLimbo the old limbo player
|
||||||
|
* @return merged limbo player if both arguments are not null, otherwise the first non-null argument
|
||||||
|
*/
|
||||||
|
LimboPlayer merge(LimboPlayer newLimbo, LimboPlayer oldLimbo) {
|
||||||
|
if (newLimbo == null) {
|
||||||
|
return oldLimbo;
|
||||||
|
} else if (oldLimbo == null) {
|
||||||
|
return newLimbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isOperator = newLimbo.isOperator() || oldLimbo.isOperator();
|
||||||
|
boolean canFly = newLimbo.isCanFly() || oldLimbo.isCanFly();
|
||||||
|
float flySpeed = Math.max(newLimbo.getFlySpeed(), oldLimbo.getFlySpeed());
|
||||||
|
float walkSpeed = Math.max(newLimbo.getWalkSpeed(), oldLimbo.getWalkSpeed());
|
||||||
|
String group = firstNotEmpty(newLimbo.getGroup(), oldLimbo.getGroup());
|
||||||
|
Location location = firstNotNull(oldLimbo.getLocation(), newLimbo.getLocation());
|
||||||
|
|
||||||
|
return new LimboPlayer(location, isOperator, group, canFly, walkSpeed, flySpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String firstNotEmpty(String newGroup, String oldGroup) {
|
||||||
|
ConsoleLogger.debug("Limbo merge: new and old perm groups are `{0}` and `{1}`", newGroup, oldGroup);
|
||||||
|
if ("".equals(oldGroup)) {
|
||||||
|
return newGroup;
|
||||||
|
}
|
||||||
|
return oldGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Location firstNotNull(Location first, Location second) {
|
||||||
|
return first == null ? second : first;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package fr.xephi.authme.data.limbo;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible types to restore the walk and fly speed from LimboPlayer
|
||||||
|
* back to Bukkit Player.
|
||||||
|
*/
|
||||||
|
public enum WalkFlySpeedRestoreType {
|
||||||
|
|
||||||
|
/** Restores from LimboPlayer to Player. */
|
||||||
|
RESTORE {
|
||||||
|
@Override
|
||||||
|
public void restoreFlySpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setFlySpeed(limbo.getFlySpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreWalkSpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setWalkSpeed(limbo.getWalkSpeed());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Restores from LimboPlayer, using the default speed if the speed on LimboPlayer is 0. */
|
||||||
|
RESTORE_NO_ZERO {
|
||||||
|
@Override
|
||||||
|
public void restoreFlySpeed(Player player, LimboPlayer limbo) {
|
||||||
|
float limboFlySpeed = limbo.getFlySpeed();
|
||||||
|
player.setFlySpeed(limboFlySpeed > 0.01f ? limboFlySpeed : LimboPlayer.DEFAULT_FLY_SPEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreWalkSpeed(Player player, LimboPlayer limbo) {
|
||||||
|
float limboWalkSpeed = limbo.getWalkSpeed();
|
||||||
|
player.setWalkSpeed(limboWalkSpeed > 0.01f ? limboWalkSpeed : LimboPlayer.DEFAULT_WALK_SPEED);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Uses the max speed of Player (current speed) and the LimboPlayer. */
|
||||||
|
MAX_RESTORE {
|
||||||
|
@Override
|
||||||
|
public void restoreFlySpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setFlySpeed(Math.max(player.getFlySpeed(), limbo.getFlySpeed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreWalkSpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setWalkSpeed(Math.max(player.getWalkSpeed(), limbo.getWalkSpeed()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Always sets the default speed to the player. */
|
||||||
|
DEFAULT {
|
||||||
|
@Override
|
||||||
|
public void restoreFlySpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setFlySpeed(LimboPlayer.DEFAULT_FLY_SPEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreWalkSpeed(Player player, LimboPlayer limbo) {
|
||||||
|
player.setWalkSpeed(LimboPlayer.DEFAULT_WALK_SPEED);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the fly speed from Limbo to Player according to the restoration type.
|
||||||
|
*
|
||||||
|
* @param player the player to modify
|
||||||
|
* @param limbo the limbo player to read from
|
||||||
|
*/
|
||||||
|
public abstract void restoreFlySpeed(Player player, LimboPlayer limbo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the walk speed from Limbo to Player according to the restoration type.
|
||||||
|
*
|
||||||
|
* @param player the player to modify
|
||||||
|
* @param limbo the limbo player to read from
|
||||||
|
*/
|
||||||
|
public abstract void restoreWalkSpeed(Player player, LimboPlayer limbo);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
|
import fr.xephi.authme.initialization.factory.Factory;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.LimboSettings;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the persistence of LimboPlayers.
|
||||||
|
*/
|
||||||
|
public class LimboPersistence implements SettingsDependent {
|
||||||
|
|
||||||
|
private final Factory<LimboPersistenceHandler> handlerFactory;
|
||||||
|
|
||||||
|
private LimboPersistenceHandler handler;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
LimboPersistence(Settings settings, Factory<LimboPersistenceHandler> handlerFactory) {
|
||||||
|
this.handlerFactory = handlerFactory;
|
||||||
|
reload(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the LimboPlayer for the given player if available.
|
||||||
|
*
|
||||||
|
* @param player the player to retrieve the LimboPlayer for
|
||||||
|
* @return the player's limbo player, or null if not available
|
||||||
|
*/
|
||||||
|
public LimboPlayer getLimboPlayer(Player player) {
|
||||||
|
try {
|
||||||
|
return handler.getLimboPlayer(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not get LimboPlayer for '" + player.getName() + "'", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the given LimboPlayer for the provided player.
|
||||||
|
*
|
||||||
|
* @param player the player to save the LimboPlayer for
|
||||||
|
* @param limbo the limbo player to save
|
||||||
|
*/
|
||||||
|
public void saveLimboPlayer(Player player, LimboPlayer limbo) {
|
||||||
|
try {
|
||||||
|
handler.saveLimboPlayer(player, limbo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not save LimboPlayer for '" + player.getName() + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the LimboPlayer for the given player.
|
||||||
|
*
|
||||||
|
* @param player the player whose LimboPlayer should be removed
|
||||||
|
*/
|
||||||
|
public void removeLimboPlayer(Player player) {
|
||||||
|
try {
|
||||||
|
handler.removeLimboPlayer(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not remove LimboPlayer for '" + player.getName() + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload(Settings settings) {
|
||||||
|
LimboPersistenceType persistenceType = settings.getProperty(LimboSettings.LIMBO_PERSISTENCE_TYPE);
|
||||||
|
// If we're changing from an existing handler, output a quick hint that nothing is converted.
|
||||||
|
if (handler != null && handler.getType() != persistenceType) {
|
||||||
|
ConsoleLogger.info("Limbo persistence type has changed! Note that the data is not converted.");
|
||||||
|
}
|
||||||
|
handler = handlerFactory.newInstance(persistenceType.getImplementationClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles I/O for storing LimboPlayer objects.
|
||||||
|
*/
|
||||||
|
interface LimboPersistenceHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the limbo player for the given player if it exists.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the stored limbo player, or null if not available
|
||||||
|
*/
|
||||||
|
LimboPlayer getLimboPlayer(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the given limbo player for the given player to the disk.
|
||||||
|
*
|
||||||
|
* @param player the player to save the limbo player for
|
||||||
|
* @param limbo the limbo player to save
|
||||||
|
*/
|
||||||
|
void saveLimboPlayer(Player player, LimboPlayer limbo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the limbo player from the disk.
|
||||||
|
*
|
||||||
|
* @param player the player whose limbo player should be removed
|
||||||
|
*/
|
||||||
|
void removeLimboPlayer(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type of the limbo persistence implementation
|
||||||
|
*/
|
||||||
|
LimboPersistenceType getType();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of persistence for LimboPlayer objects.
|
||||||
|
*/
|
||||||
|
public enum LimboPersistenceType {
|
||||||
|
|
||||||
|
/** Store each LimboPlayer in a separate file. */
|
||||||
|
INDIVIDUAL_FILES(SeparateFilePersistenceHandler.class),
|
||||||
|
|
||||||
|
/** Store all LimboPlayers in the same file. */
|
||||||
|
SINGLE_FILE(SingleFilePersistenceHandler.class),
|
||||||
|
|
||||||
|
/** Distribute LimboPlayers by segments into a set number of files. */
|
||||||
|
SEGMENT_FILES(SegmentFilesPersistenceHolder.class),
|
||||||
|
|
||||||
|
/** No persistence to disk. */
|
||||||
|
DISABLED(NoOpPersistenceHandler.class);
|
||||||
|
|
||||||
|
private final Class<? extends LimboPersistenceHandler> implementationClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param implementationClass the implementation class
|
||||||
|
*/
|
||||||
|
LimboPersistenceType(Class<? extends LimboPersistenceHandler> implementationClass) {
|
||||||
|
this.implementationClass= implementationClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return class implementing the persistence type
|
||||||
|
*/
|
||||||
|
public Class<? extends LimboPersistenceHandler> getImplementationClass() {
|
||||||
|
return implementationClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.CAN_FLY;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.FLY_SPEED;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.GROUP;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.IS_OP;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOCATION;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_PITCH;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_WORLD;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_X;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Y;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_YAW;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Z;
|
||||||
|
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.WALK_SPEED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a JsonElement to a LimboPlayer.
|
||||||
|
*/
|
||||||
|
class LimboPlayerDeserializer implements JsonDeserializer<LimboPlayer> {
|
||||||
|
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
LimboPlayerDeserializer(BukkitService bukkitService) {
|
||||||
|
this.bukkitService = bukkitService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPlayer deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) {
|
||||||
|
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||||
|
if (jsonObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location loc = deserializeLocation(jsonObject);
|
||||||
|
boolean operator = getBoolean(jsonObject, IS_OP);
|
||||||
|
String group = getString(jsonObject, GROUP);
|
||||||
|
boolean canFly = getBoolean(jsonObject, CAN_FLY);
|
||||||
|
float walkSpeed = getFloat(jsonObject, WALK_SPEED, LimboPlayer.DEFAULT_WALK_SPEED);
|
||||||
|
float flySpeed = getFloat(jsonObject, FLY_SPEED, LimboPlayer.DEFAULT_FLY_SPEED);
|
||||||
|
|
||||||
|
return new LimboPlayer(loc, operator, group, canFly, walkSpeed, flySpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Location deserializeLocation(JsonObject jsonObject) {
|
||||||
|
JsonElement e;
|
||||||
|
if ((e = jsonObject.getAsJsonObject(LOCATION)) != null) {
|
||||||
|
JsonObject locationObject = e.getAsJsonObject();
|
||||||
|
World world = bukkitService.getWorld(getString(locationObject, LOC_WORLD));
|
||||||
|
if (world != null) {
|
||||||
|
double x = getDouble(locationObject, LOC_X);
|
||||||
|
double y = getDouble(locationObject, LOC_Y);
|
||||||
|
double z = getDouble(locationObject, LOC_Z);
|
||||||
|
float yaw = getFloat(locationObject, LOC_YAW);
|
||||||
|
float pitch = getFloat(locationObject, LOC_PITCH);
|
||||||
|
return new Location(world, x, y, z, yaw, pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getString(JsonObject jsonObject, String memberName) {
|
||||||
|
JsonElement element = jsonObject.get(memberName);
|
||||||
|
return element != null ? element.getAsString() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean getBoolean(JsonObject jsonObject, String memberName) {
|
||||||
|
JsonElement element = jsonObject.get(memberName);
|
||||||
|
return element != null && element.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getFloat(JsonObject jsonObject, String memberName) {
|
||||||
|
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getFloat(JsonObject jsonObject, String memberName, float defaultValue) {
|
||||||
|
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double getDouble(JsonObject jsonObject, String memberName) {
|
||||||
|
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsDouble, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a number from the given JsonElement safely.
|
||||||
|
*
|
||||||
|
* @param jsonElement the element to retrieve the number from
|
||||||
|
* @param numberFunction the function to get the number from the element
|
||||||
|
* @param defaultValue the value to return if the element is null or the number cannot be retrieved
|
||||||
|
* @param <N> the number type
|
||||||
|
* @return the number from the given JSON element, or the default value
|
||||||
|
*/
|
||||||
|
private static <N extends Number> N getNumberFromElement(JsonElement jsonElement,
|
||||||
|
Function<JsonElement, N> numberFunction,
|
||||||
|
N defaultValue) {
|
||||||
|
if (jsonElement != null) {
|
||||||
|
try {
|
||||||
|
return numberFunction.apply(jsonElement);
|
||||||
|
} catch (NumberFormatException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a LimboPlayer to a JsonElement.
|
||||||
|
*/
|
||||||
|
class LimboPlayerSerializer implements JsonSerializer<LimboPlayer> {
|
||||||
|
|
||||||
|
static final String LOCATION = "location";
|
||||||
|
static final String LOC_WORLD = "world";
|
||||||
|
static final String LOC_X = "x";
|
||||||
|
static final String LOC_Y = "y";
|
||||||
|
static final String LOC_Z = "z";
|
||||||
|
static final String LOC_YAW = "yaw";
|
||||||
|
static final String LOC_PITCH = "pitch";
|
||||||
|
|
||||||
|
static final String GROUP = "group";
|
||||||
|
static final String IS_OP = "operator";
|
||||||
|
static final String CAN_FLY = "can-fly";
|
||||||
|
static final String WALK_SPEED = "walk-speed";
|
||||||
|
static final String FLY_SPEED = "fly-speed";
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(LimboPlayer limboPlayer, Type type, JsonSerializationContext context) {
|
||||||
|
Location loc = limboPlayer.getLocation();
|
||||||
|
JsonObject locationObject = new JsonObject();
|
||||||
|
locationObject.addProperty(LOC_WORLD, loc.getWorld().getName());
|
||||||
|
locationObject.addProperty(LOC_X, loc.getX());
|
||||||
|
locationObject.addProperty(LOC_Y, loc.getY());
|
||||||
|
locationObject.addProperty(LOC_Z, loc.getZ());
|
||||||
|
locationObject.addProperty(LOC_YAW, loc.getYaw());
|
||||||
|
locationObject.addProperty(LOC_PITCH, loc.getPitch());
|
||||||
|
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.add(LOCATION, locationObject);
|
||||||
|
obj.addProperty(GROUP, limboPlayer.getGroup());
|
||||||
|
obj.addProperty(IS_OP, limboPlayer.isOperator());
|
||||||
|
obj.addProperty(CAN_FLY, limboPlayer.isCanFly());
|
||||||
|
obj.addProperty(WALK_SPEED, limboPlayer.getWalkSpeed());
|
||||||
|
obj.addProperty(FLY_SPEED, limboPlayer.getFlySpeed());
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limbo player persistence implementation that does nothing.
|
||||||
|
*/
|
||||||
|
class NoOpPersistenceHandler implements LimboPersistenceHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPlayer getLimboPlayer(Player player) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveLimboPlayer(Player player, LimboPlayer limbo) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeLimboPlayer(Player player) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPersistenceType getType() {
|
||||||
|
return LimboPersistenceType.DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the total number of segments to use.
|
||||||
|
* <p>
|
||||||
|
* The {@link SegmentFilesPersistenceHolder} reduces the number of files by assigning each UUID
|
||||||
|
* to a segment. This enum allows to define how many segments the UUIDs should be distributed in.
|
||||||
|
* <p>
|
||||||
|
* Segments are defined by a <b>distribution</b> and a <b>length.</b> The distribution defines
|
||||||
|
* to how many outputs a single hexadecimal characters should be mapped. So e.g. a distribution
|
||||||
|
* of 3 means that all hexadecimal characters 0-f should be distributed over three different
|
||||||
|
* outputs evenly. The {@link SegmentNameBuilder} simply uses hexadecimal characters as outputs,
|
||||||
|
* so e.g. with a distribution of 3 all hex characters 0-f are mapped to 0, 1, or 2.
|
||||||
|
* <p>
|
||||||
|
* To ensure an even distribution the segments must be powers of 2. Trivially, to implement a
|
||||||
|
* distribution of 16, the same character may be returned as was input (since 0-f make up 16
|
||||||
|
* characters). A distribution of 1, on the other hand, means that the same output is returned
|
||||||
|
* regardless of the input character.
|
||||||
|
* <p>
|
||||||
|
* The <b>length</b> parameter defines how many characters of a player's UUID should be used to
|
||||||
|
* create the segment ID. In other words, with a distribution of 2 and a length of 3, the first
|
||||||
|
* three characters of the UUID are taken into consideration, each mapped to one of two possible
|
||||||
|
* characters. For instance, a UUID starting with "0f5c9321" may yield the segment ID "010."
|
||||||
|
* Such a segment ID defines in which file the given UUID can be found and stored.
|
||||||
|
* <p>
|
||||||
|
* The number of segments such a configuration yields is computed as {@code distribution ^ length},
|
||||||
|
* since distribution defines how many outputs there are per digit, and length defines the number
|
||||||
|
* of digits. For instance, a distribution of 2 and a length of 3 will yield segment IDs 000, 001,
|
||||||
|
* 010, 011, 100, 101, 110 and 111 (i.e. all binary numbers from 0 to 7).
|
||||||
|
* <p>
|
||||||
|
* There are multiple possibilities to achieve certain segment totals, e.g. 8 different segments
|
||||||
|
* may be created by setting distribution to 8 and length to 1, or distr. to 2 and length to 3.
|
||||||
|
* Where possible, prefer a length of 1 (no string concatenation required) or a distribution of
|
||||||
|
* 16 (no remapping of the characters required).
|
||||||
|
*/
|
||||||
|
public enum SegmentConfiguration {
|
||||||
|
|
||||||
|
/** 1. */
|
||||||
|
ONE(1, 1),
|
||||||
|
|
||||||
|
///** 2. */
|
||||||
|
//TWO(2, 1),
|
||||||
|
|
||||||
|
/** 4. */
|
||||||
|
FOUR(4, 1),
|
||||||
|
|
||||||
|
/** 8. */
|
||||||
|
EIGHT(8, 1),
|
||||||
|
|
||||||
|
/** 16. */
|
||||||
|
SIXTEEN(16, 1),
|
||||||
|
|
||||||
|
/** 32. */
|
||||||
|
THIRTY_TWO(2, 5),
|
||||||
|
|
||||||
|
/** 64. */
|
||||||
|
SIXTY_FOUR(4, 3),
|
||||||
|
|
||||||
|
/** 128. */
|
||||||
|
ONE_TWENTY(2, 7),
|
||||||
|
|
||||||
|
/** 256. */
|
||||||
|
TWO_FIFTY(16, 2);
|
||||||
|
|
||||||
|
private final int distribution;
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
SegmentConfiguration(int distribution, int length) {
|
||||||
|
this.distribution = distribution;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the distribution size per character, i.e. how many possible outputs there are
|
||||||
|
* for any hexadecimal character
|
||||||
|
*/
|
||||||
|
public int getDistribution() {
|
||||||
|
return distribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return number of characters from a UUID that should be used to create a segment ID
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return number of segments to which this configuration will distribute UUIDs
|
||||||
|
*/
|
||||||
|
public int getTotalSegments() {
|
||||||
|
return (int) Math.pow(distribution, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,226 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.LimboSettings;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistence handler for LimboPlayer objects by distributing the objects to store
|
||||||
|
* in various segments (buckets) based on the start of the player's UUID.
|
||||||
|
*/
|
||||||
|
class SegmentFilesPersistenceHolder implements LimboPersistenceHandler {
|
||||||
|
|
||||||
|
private static final Type LIMBO_MAP_TYPE = new TypeToken<Map<String, LimboPlayer>>(){}.getType();
|
||||||
|
|
||||||
|
private final File cacheFolder;
|
||||||
|
private final Gson gson;
|
||||||
|
private final SegmentNameBuilder segmentNameBuilder;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SegmentFilesPersistenceHolder(@DataFolder File dataFolder, BukkitService bukkitService, Settings settings) {
|
||||||
|
cacheFolder = new File(dataFolder, "playerdata");
|
||||||
|
if (!cacheFolder.exists()) {
|
||||||
|
// TODO ljacqu 20170313: Create FileUtils#mkdirs
|
||||||
|
cacheFolder.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService))
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
segmentNameBuilder = new SegmentNameBuilder(settings.getProperty(LimboSettings.SEGMENT_DISTRIBUTION));
|
||||||
|
|
||||||
|
convertOldDataToCurrentSegmentScheme();
|
||||||
|
deleteEmptyFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPlayer getLimboPlayer(Player player) {
|
||||||
|
String uuid = PlayerUtils.getUUIDorName(player);
|
||||||
|
File file = getPlayerSegmentFile(uuid);
|
||||||
|
Map<String, LimboPlayer> entries = readLimboPlayers(file);
|
||||||
|
return entries == null ? null : entries.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveLimboPlayer(Player player, LimboPlayer limbo) {
|
||||||
|
String uuid = PlayerUtils.getUUIDorName(player);
|
||||||
|
File file = getPlayerSegmentFile(uuid);
|
||||||
|
|
||||||
|
Map<String, LimboPlayer> entries = null;
|
||||||
|
if (file.exists()) {
|
||||||
|
entries = readLimboPlayers(file);
|
||||||
|
} else {
|
||||||
|
FileUtils.create(file);
|
||||||
|
}
|
||||||
|
/* intentionally separate if */
|
||||||
|
if (entries == null) {
|
||||||
|
entries = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.put(PlayerUtils.getUUIDorName(player), limbo);
|
||||||
|
saveEntries(entries, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeLimboPlayer(Player player) {
|
||||||
|
String uuid = PlayerUtils.getUUIDorName(player);
|
||||||
|
File file = getPlayerSegmentFile(uuid);
|
||||||
|
if (file.exists()) {
|
||||||
|
Map<String, LimboPlayer> entries = readLimboPlayers(file);
|
||||||
|
if (entries != null && entries.remove(PlayerUtils.getUUIDorName(player)) != null) {
|
||||||
|
saveEntries(entries, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPersistenceType getType() {
|
||||||
|
return LimboPersistenceType.SEGMENT_FILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveEntries(Map<String, LimboPlayer> entries, File file) {
|
||||||
|
try (FileWriter fw = new FileWriter(file)) {
|
||||||
|
gson.toJson(entries, fw);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Could not write to '" + file + "':", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, LimboPlayer> readLimboPlayers(File file) {
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return gson.fromJson(Files.toString(file, StandardCharsets.UTF_8), LIMBO_MAP_TYPE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Failed reading '" + file + "':", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getPlayerSegmentFile(String uuid) {
|
||||||
|
String segment = segmentNameBuilder.createSegmentName(uuid);
|
||||||
|
return new File(cacheFolder, segment + "-limbo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads segment files in the cache folder that don't correspond to the current segmenting scheme
|
||||||
|
* and migrates the data into files of the current segments. This allows a player to change the
|
||||||
|
* segment size without any loss of data.
|
||||||
|
*/
|
||||||
|
private void convertOldDataToCurrentSegmentScheme() {
|
||||||
|
String currentPrefix = segmentNameBuilder.getPrefix();
|
||||||
|
File[] files = listFiles(cacheFolder);
|
||||||
|
Map<String, LimboPlayer> allLimboPlayers = new HashMap<>();
|
||||||
|
List<File> migratedFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
if (isLimboJsonFile(file) && !file.getName().startsWith(currentPrefix)) {
|
||||||
|
Map<String, LimboPlayer> data = readLimboPlayers(file);
|
||||||
|
if (data != null) {
|
||||||
|
allLimboPlayers.putAll(data);
|
||||||
|
migratedFiles.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allLimboPlayers.isEmpty()) {
|
||||||
|
saveToNewSegments(allLimboPlayers);
|
||||||
|
migratedFiles.forEach(FileUtils::delete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the LimboPlayer data read from old segmenting schemes into the current segmenting scheme.
|
||||||
|
*
|
||||||
|
* @param limbosFromOldSegments the limbo players to store into the current segment files
|
||||||
|
*/
|
||||||
|
private void saveToNewSegments(Map<String, LimboPlayer> limbosFromOldSegments) {
|
||||||
|
Map<String, Map<String, LimboPlayer>> limboBySegment = groupBySegment(limbosFromOldSegments);
|
||||||
|
|
||||||
|
ConsoleLogger.info("Saving " + limbosFromOldSegments.size() + " LimboPlayers from old segments into "
|
||||||
|
+ limboBySegment.size() + " current segments");
|
||||||
|
for (Map.Entry<String, Map<String, LimboPlayer>> entry : limboBySegment.entrySet()) {
|
||||||
|
File file = new File(cacheFolder, entry.getKey() + "-limbo.json");
|
||||||
|
Map<String, LimboPlayer> limbosToSave = Optional.ofNullable(readLimboPlayers(file))
|
||||||
|
.orElseGet(HashMap::new);
|
||||||
|
limbosToSave.putAll(entry.getValue());
|
||||||
|
saveEntries(limbosToSave, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Map of UUID to LimboPlayers to a 2-dimensional Map of LimboPlayers by segment ID and UUID.
|
||||||
|
* {@code Map(uuid -> LimboPlayer) to Map(segment -> Map(uuid -> LimboPlayer))}
|
||||||
|
*
|
||||||
|
* @param readLimboPlayers the limbo players to order by segment
|
||||||
|
* @return limbo players ordered by segment ID and associated player UUID
|
||||||
|
*/
|
||||||
|
private Map<String, Map<String, LimboPlayer>> groupBySegment(Map<String, LimboPlayer> readLimboPlayers) {
|
||||||
|
Map<String, Map<String, LimboPlayer>> limboBySegment = new HashMap<>();
|
||||||
|
for (Map.Entry<String, LimboPlayer> entry : readLimboPlayers.entrySet()) {
|
||||||
|
String segmentId = segmentNameBuilder.createSegmentName(entry.getKey());
|
||||||
|
limboBySegment.computeIfAbsent(segmentId, s -> new HashMap<>())
|
||||||
|
.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return limboBySegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes files from the current segmenting scheme that are empty.
|
||||||
|
*/
|
||||||
|
private void deleteEmptyFiles() {
|
||||||
|
File[] files = listFiles(cacheFolder);
|
||||||
|
|
||||||
|
long deletedFiles = Arrays.stream(files)
|
||||||
|
// typically the size is 2 because there's an empty JSON map: {}
|
||||||
|
.filter(f -> isLimboJsonFile(f) && f.length() < 3)
|
||||||
|
.peek(FileUtils::delete)
|
||||||
|
.count();
|
||||||
|
ConsoleLogger.debug("Limbo: Deleted {0} empty segment files", deletedFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param file the file to check
|
||||||
|
* @return true if it is a segment file storing Limbo data, false otherwise
|
||||||
|
*/
|
||||||
|
private static boolean isLimboJsonFile(File file) {
|
||||||
|
String name = file.getName();
|
||||||
|
return name.startsWith("seg") && name.endsWith("-limbo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File[] listFiles(File folder) {
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
ConsoleLogger.warning("Could not get files of '" + folder + "'");
|
||||||
|
return new File[0];
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates segment names for {@link SegmentFilesPersistenceHolder}.
|
||||||
|
*/
|
||||||
|
class SegmentNameBuilder {
|
||||||
|
|
||||||
|
private final int length;
|
||||||
|
private final int distribution;
|
||||||
|
private final String prefix;
|
||||||
|
private final Map<Character, Character> charToSegmentChar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param partition the segment configuration
|
||||||
|
*/
|
||||||
|
SegmentNameBuilder(SegmentConfiguration partition) {
|
||||||
|
this.length = partition.getLength();
|
||||||
|
this.distribution = partition.getDistribution();
|
||||||
|
this.prefix = "seg" + partition.getTotalSegments() + "-";
|
||||||
|
this.charToSegmentChar = buildCharMap(distribution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the segment ID for the given UUID.
|
||||||
|
*
|
||||||
|
* @param uuid the player's uuid to get the segment for
|
||||||
|
* @return id the uuid belongs to
|
||||||
|
*/
|
||||||
|
String createSegmentName(String uuid) {
|
||||||
|
if (distribution == 16) {
|
||||||
|
return prefix + uuid.substring(0, length);
|
||||||
|
} else {
|
||||||
|
return prefix + buildSegmentName(uuid.substring(0, length).toCharArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the prefix used for the current segment configuration
|
||||||
|
*/
|
||||||
|
String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSegmentName(char[] chars) {
|
||||||
|
if (chars.length == 1) {
|
||||||
|
return String.valueOf(charToSegmentChar.get(chars[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(chars.length);
|
||||||
|
for (char chr : chars) {
|
||||||
|
sb.append(charToSegmentChar.get(chr));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Character, Character> buildCharMap(int distribution) {
|
||||||
|
final char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
|
final int divisor = 16 / distribution;
|
||||||
|
|
||||||
|
Map<Character, Character> charToSegmentChar = new HashMap<>();
|
||||||
|
for (int i = 0; i < hexChars.length; ++i) {
|
||||||
|
int mappedChar = i / divisor;
|
||||||
|
charToSegmentChar.put(hexChars[i], hexChars[mappedChar]);
|
||||||
|
}
|
||||||
|
return charToSegmentChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves LimboPlayer objects as JSON into individual files.
|
||||||
|
*/
|
||||||
|
class SeparateFilePersistenceHandler implements LimboPersistenceHandler {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final File cacheDir;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SeparateFilePersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService) {
|
||||||
|
cacheDir = new File(dataFolder, "playerdata");
|
||||||
|
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
|
||||||
|
ConsoleLogger.warning("Failed to create playerdata directory '" + cacheDir + "'");
|
||||||
|
}
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService))
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPlayer getLimboPlayer(Player player) {
|
||||||
|
String id = PlayerUtils.getUUIDorName(player);
|
||||||
|
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String str = Files.toString(file, StandardCharsets.UTF_8);
|
||||||
|
return gson.fromJson(str, LimboPlayer.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Could not read player data on disk for '" + player.getName() + "'", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveLimboPlayer(Player player, LimboPlayer limboPlayer) {
|
||||||
|
String id = PlayerUtils.getUUIDorName(player);
|
||||||
|
try {
|
||||||
|
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||||
|
Files.createParentDirs(file);
|
||||||
|
Files.touch(file);
|
||||||
|
Files.write(gson.toJson(limboPlayer), file, StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Failed to write " + player.getName() + " data:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the LimboPlayer. This will delete the
|
||||||
|
* "playerdata/<uuid or name>/" folder from disk.
|
||||||
|
*
|
||||||
|
* @param player player to remove
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void removeLimboPlayer(Player player) {
|
||||||
|
String id = PlayerUtils.getUUIDorName(player);
|
||||||
|
File file = new File(cacheDir, id);
|
||||||
|
if (file.exists()) {
|
||||||
|
FileUtils.purgeDirectory(file);
|
||||||
|
FileUtils.delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPersistenceType getType() {
|
||||||
|
return LimboPersistenceType.INDIVIDUAL_FILES;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package fr.xephi.authme.data.limbo.persistence;
|
||||||
|
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all LimboPlayers in one JSON file and keeps the entries in memory.
|
||||||
|
*/
|
||||||
|
class SingleFilePersistenceHandler implements LimboPersistenceHandler {
|
||||||
|
|
||||||
|
private final File cacheFile;
|
||||||
|
private final Gson gson;
|
||||||
|
private Map<String, LimboPlayer> entries;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SingleFilePersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService) {
|
||||||
|
cacheFile = new File(dataFolder, "limbo.json");
|
||||||
|
if (!cacheFile.exists()) {
|
||||||
|
FileUtils.create(cacheFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||||
|
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService))
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
Type type = new TypeToken<ConcurrentMap<String, LimboPlayer>>(){}.getType();
|
||||||
|
try (FileReader fr = new FileReader(cacheFile)) {
|
||||||
|
entries = gson.fromJson(fr, type);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Failed to read from '" + cacheFile + "':", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries == null) {
|
||||||
|
entries = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPlayer getLimboPlayer(Player player) {
|
||||||
|
return entries.get(PlayerUtils.getUUIDorName(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveLimboPlayer(Player player, LimboPlayer limbo) {
|
||||||
|
entries.put(PlayerUtils.getUUIDorName(player), limbo);
|
||||||
|
saveEntries("adding '" + player.getName() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeLimboPlayer(Player player) {
|
||||||
|
LimboPlayer entry = entries.remove(PlayerUtils.getUUIDorName(player));
|
||||||
|
if (entry != null) {
|
||||||
|
saveEntries("removing '" + player.getName() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the entries to the disk.
|
||||||
|
*
|
||||||
|
* @param action the reason for saving (for logging purposes)
|
||||||
|
*/
|
||||||
|
private void saveEntries(String action) {
|
||||||
|
try (FileWriter fw = new FileWriter(cacheFile)) {
|
||||||
|
gson.toJson(entries, fw);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Failed saving JSON limbo cache after " + action, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimboPersistenceType getType() {
|
||||||
|
return LimboPersistenceType.SINGLE_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import fr.xephi.authme.ConsoleLogger;
|
|||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.security.HashAlgorithm;
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.security.crypts.XFBCRYPT;
|
import fr.xephi.authme.security.crypts.XfBCrypt;
|
||||||
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.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
@ -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,6 +99,9 @@ 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) {
|
||||||
@ -286,7 +292,7 @@ public class MySQL implements DataSource {
|
|||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
Blob blob = rs.getBlob("data");
|
Blob blob = rs.getBlob("data");
|
||||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||||
auth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
auth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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,17 +516,51 @@ 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);
|
||||||
pst2.setString(2, XFBCRYPT.SCHEME_CLASS);
|
pst2.setString(2, XfBCrypt.SCHEME_CLASS);
|
||||||
String serializedHash = XFBCRYPT.serializeHash(auth.getPassword().getHash());
|
String serializedHash = XfBCrypt.serializeHash(auth.getPassword().getHash());
|
||||||
byte[] bytes = serializedHash.getBytes();
|
byte[] bytes = serializedHash.getBytes();
|
||||||
Blob blob = con.createBlob();
|
Blob blob = con.createBlob();
|
||||||
blob.setBytes(1, bytes);
|
blob.setBytes(1, bytes);
|
||||||
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();
|
||||||
@ -538,7 +609,7 @@ public class MySQL implements DataSource {
|
|||||||
// Insert password in the correct table
|
// Insert password in the correct table
|
||||||
sql = "UPDATE xf_user_authenticate SET data=? WHERE " + col.ID + "=?;";
|
sql = "UPDATE xf_user_authenticate SET data=? WHERE " + col.ID + "=?;";
|
||||||
PreparedStatement pst2 = con.prepareStatement(sql);
|
PreparedStatement pst2 = con.prepareStatement(sql);
|
||||||
String serializedHash = XFBCRYPT.serializeHash(password.getHash());
|
String serializedHash = XfBCrypt.serializeHash(password.getHash());
|
||||||
byte[] bytes = serializedHash.getBytes();
|
byte[] bytes = serializedHash.getBytes();
|
||||||
Blob blob = con.createBlob();
|
Blob blob = con.createBlob();
|
||||||
blob.setBytes(1, bytes);
|
blob.setBytes(1, bytes);
|
||||||
@ -549,7 +620,7 @@ public class MySQL implements DataSource {
|
|||||||
// ...
|
// ...
|
||||||
sql = "UPDATE xf_user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;";
|
sql = "UPDATE xf_user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;";
|
||||||
pst2 = con.prepareStatement(sql);
|
pst2 = con.prepareStatement(sql);
|
||||||
pst2.setString(1, XFBCRYPT.SCHEME_CLASS);
|
pst2.setString(1, XfBCrypt.SCHEME_CLASS);
|
||||||
pst2.setInt(2, id);
|
pst2.setInt(2, id);
|
||||||
pst2.executeUpdate();
|
pst2.executeUpdate();
|
||||||
pst2.close();
|
pst2.close();
|
||||||
@ -824,7 +895,7 @@ public class MySQL implements DataSource {
|
|||||||
if (rs2.next()) {
|
if (rs2.next()) {
|
||||||
Blob blob = rs2.getBlob("data");
|
Blob blob = rs2.getBlob("data");
|
||||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
pAuth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes)));
|
||||||
}
|
}
|
||||||
rs2.close();
|
rs2.close();
|
||||||
}
|
}
|
||||||
@ -856,7 +927,7 @@ public class MySQL implements DataSource {
|
|||||||
if (rs2.next()) {
|
if (rs2.next()) {
|
||||||
Blob blob = rs2.getBlob("data");
|
Blob blob = rs2.getBlob("data");
|
||||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
pAuth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes)));
|
||||||
}
|
}
|
||||||
rs2.close();
|
rs2.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -16,13 +16,13 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static fr.xephi.authme.util.FileUtils.makePath;
|
import static fr.xephi.authme.util.FileUtils.makePath;
|
||||||
|
|
||||||
public class vAuthConverter implements Converter {
|
public class VAuthConverter implements Converter {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final File vAuthPasswordsFile;
|
private final File vAuthPasswordsFile;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
VAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
||||||
vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
|
vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static fr.xephi.authme.util.FileUtils.makePath;
|
import static fr.xephi.authme.util.FileUtils.makePath;
|
||||||
|
|
||||||
public class xAuthConverter implements Converter {
|
public class XAuthConverter implements Converter {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@DataFolder
|
@DataFolder
|
||||||
@ -31,7 +31,7 @@ public class xAuthConverter implements Converter {
|
|||||||
@Inject
|
@Inject
|
||||||
private PluginManager pluginManager;
|
private PluginManager pluginManager;
|
||||||
|
|
||||||
xAuthConverter() {
|
XAuthConverter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2,15 +2,14 @@ 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.limbo.LimboPlayerStorage;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.PluginHookService;
|
import fr.xephi.authme.service.PluginHookService;
|
||||||
|
import fr.xephi.authme.service.ValidationService;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.service.ValidationService;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@ -28,17 +27,15 @@ public class OnShutdownPlayerSaver {
|
|||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
|
||||||
@Inject
|
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
@Inject
|
@Inject
|
||||||
private LimboPlayerStorage limboPlayerStorage;
|
|
||||||
@Inject
|
|
||||||
private SpawnLoader spawnLoader;
|
private SpawnLoader spawnLoader;
|
||||||
@Inject
|
@Inject
|
||||||
private PluginHookService pluginHookService;
|
private PluginHookService pluginHookService;
|
||||||
@Inject
|
@Inject
|
||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
@Inject
|
||||||
|
private LimboService limboService;
|
||||||
|
|
||||||
OnShutdownPlayerSaver() {
|
OnShutdownPlayerSaver() {
|
||||||
}
|
}
|
||||||
@ -57,9 +54,8 @@ public class OnShutdownPlayerSaver {
|
|||||||
if (pluginHookService.isNpc(player) || validationService.isUnrestricted(name)) {
|
if (pluginHookService.isNpc(player) || validationService.isUnrestricted(name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (limboCache.hasPlayerData(name)) {
|
if (limboService.hasLimboPlayer(name)) {
|
||||||
limboCache.restoreData(player);
|
limboService.restoreData(player);
|
||||||
limboCache.removeFromCache(player);
|
|
||||||
} else {
|
} else {
|
||||||
saveLoggedinPlayer(player);
|
saveLoggedinPlayer(player);
|
||||||
}
|
}
|
||||||
@ -75,9 +71,5 @@ public class OnShutdownPlayerSaver {
|
|||||||
.location(loc).build();
|
.location(loc).build();
|
||||||
dataSource.updateQuitLoc(auth);
|
dataSource.updateQuitLoc(auth);
|
||||||
}
|
}
|
||||||
if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
|
|
||||||
&& !settings.getProperty(RestrictionSettings.NO_TELEPORT) && !limboPlayerStorage.hasData(player)) {
|
|
||||||
limboPlayerStorage.saveData(player);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,12 @@ 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) {
|
||||||
final Metrics metrics = new Metrics(plugin);
|
final Metrics metrics = new Metrics(plugin);
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,8 @@ public class FactoryDependencyHandler implements DependencyHandler {
|
|||||||
if (dependencyDescription.getType() == Factory.class) {
|
if (dependencyDescription.getType() == Factory.class) {
|
||||||
Class<?> genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType());
|
Class<?> genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType());
|
||||||
if (genericType == null) {
|
if (genericType == null) {
|
||||||
throw new IllegalStateException("Factory fields must have concrete generic type. " +
|
throw new IllegalStateException("Factory fields must have concrete generic type. "
|
||||||
"Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
+ "Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FactoryImpl<>(genericType, context.getInjector());
|
return new FactoryImpl<>(genericType, context.getInjector());
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package fr.xephi.authme.initialization.factory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injectable object to retrieve and create singletons of a common parent.
|
||||||
|
*
|
||||||
|
* @param <P> the parent class to which this store is limited to
|
||||||
|
*/
|
||||||
|
public interface SingletonStore<P> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the singleton of the given type, creating it if it hasn't been yet created.
|
||||||
|
*
|
||||||
|
* @param clazz the class to get the singleton for
|
||||||
|
* @param <C> type of the singleton
|
||||||
|
* @return the singleton of type {@code C}
|
||||||
|
*/
|
||||||
|
<C extends P> C getSingleton(Class<C> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all existing singletons of this store's type.
|
||||||
|
*
|
||||||
|
* @return all registered singletons of type {@code P}
|
||||||
|
*/
|
||||||
|
Collection<P> retrieveAllOfType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all existing singletons of the given type.
|
||||||
|
*
|
||||||
|
* @param clazz the type to get singletons for
|
||||||
|
* @param <C> class type
|
||||||
|
* @return all registered singletons of type {@code C}
|
||||||
|
*/
|
||||||
|
<C extends P> Collection<C> retrieveAllOfType(Class<C> clazz);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency handler that builds {@link SingletonStore} objects.
|
||||||
|
*/
|
||||||
|
public class SingletonStoreDependencyHandler implements DependencyHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveValue(ResolvedInstantiationContext<?> context, DependencyDescription dependencyDescription) {
|
||||||
|
if (dependencyDescription.getType() == SingletonStore.class) {
|
||||||
|
Class<?> genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType());
|
||||||
|
if (genericType == null) {
|
||||||
|
throw new IllegalStateException("Singleton store fields must have concrete generic type. "
|
||||||
|
+ "Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SingletonStoreImpl<>(genericType, context.getInjector());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class SingletonStoreImpl<P> implements SingletonStore<P> {
|
||||||
|
|
||||||
|
private final Injector injector;
|
||||||
|
private final Class<P> parentClass;
|
||||||
|
|
||||||
|
SingletonStoreImpl(Class<P> parentClass, Injector injector) {
|
||||||
|
this.parentClass = parentClass;
|
||||||
|
this.injector = injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <C extends P> C getSingleton(Class<C> clazz) {
|
||||||
|
if (parentClass.isAssignableFrom(clazz)) {
|
||||||
|
return injector.getSingleton(clazz);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(clazz + " not child of " + parentClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<P> retrieveAllOfType() {
|
||||||
|
return retrieveAllOfType(parentClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <C extends P> Collection<C> retrieveAllOfType(Class<C> clazz) {
|
||||||
|
if (parentClass.isAssignableFrom(clazz)) {
|
||||||
|
return injector.retrieveAllOfType(clazz);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(clazz + " not child of " + parentClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -111,7 +111,7 @@ class OnJoinVerifier implements Reloadable {
|
|||||||
* @param event the login event to verify
|
* @param event the login event to verify
|
||||||
*
|
*
|
||||||
* @return true if the player's connection should be refused (i.e. the event does not need to be processed
|
* @return true if the player's connection should be refused (i.e. the event does not need to be processed
|
||||||
* further), false if the player is not refused
|
* further), false if the player is not refused
|
||||||
*/
|
*/
|
||||||
public boolean refusePlayerForFullServer(PlayerLoginEvent event) {
|
public boolean refusePlayerForFullServer(PlayerLoginEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package fr.xephi.authme.mail;
|
package fr.xephi.authme.mail;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
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.PluginSettings;
|
||||||
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;
|
||||||
@ -56,6 +58,9 @@ 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;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package fr.xephi.authme.permission;
|
package fr.xephi.authme.permission;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
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.data.limbo.LimboService;
|
||||||
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.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
@ -33,7 +33,7 @@ public class AuthGroupHandler implements Reloadable {
|
|||||||
private Settings settings;
|
private Settings settings;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
private String unregisteredGroup;
|
private String unregisteredGroup;
|
||||||
private String registeredGroup;
|
private String registeredGroup;
|
||||||
@ -53,7 +53,7 @@ public class AuthGroupHandler implements Reloadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String primaryGroup = Optional
|
String primaryGroup = Optional
|
||||||
.ofNullable(limboCache.getPlayerData(player.getName()))
|
.ofNullable(limboService.getLimboPlayer(player.getName()))
|
||||||
.map(LimboPlayer::getGroup)
|
.map(LimboPlayer::getGroup)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
|
|
||||||
|
|||||||
@ -31,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
|
||||||
@ -46,17 +47,19 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
|||||||
|
|
||||||
@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());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,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
|
||||||
@ -41,20 +42,23 @@ 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
|
@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
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import fr.xephi.authme.process.login.AsynchronousLogin;
|
|||||||
import fr.xephi.authme.process.logout.AsynchronousLogout;
|
import fr.xephi.authme.process.logout.AsynchronousLogout;
|
||||||
import fr.xephi.authme.process.quit.AsynchronousQuit;
|
import fr.xephi.authme.process.quit.AsynchronousQuit;
|
||||||
import fr.xephi.authme.process.register.AsyncRegister;
|
import fr.xephi.authme.process.register.AsyncRegister;
|
||||||
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
|
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
||||||
|
import fr.xephi.authme.process.register.executors.RegistrationParameters;
|
||||||
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
|
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
|
||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -60,8 +61,8 @@ public class Management {
|
|||||||
runTask(() -> asynchronousLogout.logout(player));
|
runTask(() -> asynchronousLogout.logout(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performRegister(Player player, RegistrationExecutor registrationExecutor) {
|
public <P extends RegistrationParameters> void performRegister(RegistrationMethod<P> variant, P parameters) {
|
||||||
runTask(() -> asyncRegister.register(player, registrationExecutor));
|
runTask(() -> asyncRegister.register(variant, parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performUnregister(Player player, String password) {
|
public void performUnregister(Player player, String password) {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ 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;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
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.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
@ -15,12 +15,12 @@ import fr.xephi.authme.process.login.AsynchronousLogin;
|
|||||||
import fr.xephi.authme.service.BukkitService;
|
import fr.xephi.authme.service.BukkitService;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.service.PluginHookService;
|
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.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
@ -51,7 +51,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SessionManager sessionManager;
|
private SessionManager sessionManager;
|
||||||
@ -62,15 +62,15 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
@Inject
|
@Inject
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AsynchronousLogin asynchronousLogin;
|
private AsynchronousLogin asynchronousLogin;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
|
||||||
AsynchronousJoin() {
|
AsynchronousJoin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ 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() {
|
||||||
@ -111,7 +111,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
final boolean isAuthAvailable = database.isAuthAvailable(name);
|
final boolean isAuthAvailable = database.isAuthAvailable(name);
|
||||||
|
|
||||||
if (isAuthAvailable) {
|
if (isAuthAvailable) {
|
||||||
limboCache.addPlayerData(player);
|
|
||||||
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
|
|
||||||
// Protect inventory
|
// Protect inventory
|
||||||
@ -141,10 +140,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not Registered. Delete old data, load default one.
|
|
||||||
limboCache.deletePlayerData(player);
|
|
||||||
limboCache.addPlayerData(player);
|
|
||||||
|
|
||||||
// Groups logic
|
// Groups logic
|
||||||
service.setGroup(player, AuthGroupType.UNREGISTERED);
|
service.setGroup(player, AuthGroupType.UNREGISTERED);
|
||||||
|
|
||||||
@ -157,12 +152,8 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||||
|
|
||||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
||||||
player.setOp(false);
|
limboService.createLimboPlayer(player, isAuthAvailable);
|
||||||
if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
|
|
||||||
&& service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
|
||||||
player.setFlySpeed(0.0f);
|
|
||||||
player.setWalkSpeed(0.0f);
|
|
||||||
}
|
|
||||||
player.setNoDamageTicks(registrationTimeout);
|
player.setNoDamageTicks(registrationTimeout);
|
||||||
if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
|
if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
|
||||||
player.performCommand("motd");
|
player.performCommand("motd");
|
||||||
@ -174,40 +165,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
|||||||
}
|
}
|
||||||
commandManager.runCommandsOnJoin(player);
|
commandManager.runCommandsOnJoin(player);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Timeout and message task
|
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -6,26 +6,23 @@ import fr.xephi.authme.data.CaptchaManager;
|
|||||||
import fr.xephi.authme.data.TempbanManager;
|
import fr.xephi.authme.data.TempbanManager;
|
||||||
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.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
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;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.SyncProcessManager;
|
import fr.xephi.authme.process.SyncProcessManager;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
import fr.xephi.authme.settings.properties.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.task.LimboPlayerTaskManager;
|
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.util.PlayerUtils;
|
import fr.xephi.authme.util.PlayerUtils;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -46,15 +43,9 @@ 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;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboCache limboCache;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SyncProcessManager syncProcessManager;
|
private SyncProcessManager syncProcessManager;
|
||||||
|
|
||||||
@ -71,7 +62,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
private TempbanManager tempbanManager;
|
private TempbanManager tempbanManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
private LimboService limboService;
|
||||||
|
|
||||||
AsynchronousLogin() {
|
AsynchronousLogin() {
|
||||||
}
|
}
|
||||||
@ -119,8 +110,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
if (auth == null) {
|
if (auth == null) {
|
||||||
service.send(player, MessageKey.UNKNOWN_USER);
|
service.send(player, MessageKey.UNKNOWN_USER);
|
||||||
// Recreate the message task to immediately send the message again as response
|
// Recreate the message task to immediately send the message again as response
|
||||||
// and to make sure we send the right register message (password vs. email registration)
|
limboService.resetMessageTask(player, false);
|
||||||
limboPlayerTaskManager.registerMessageTask(name, false);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +185,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
|
|
||||||
// If the authentication fails check if Captcha is required and send a message to the player
|
// If the authentication fails check if Captcha is required and send a message to the player
|
||||||
if (captchaManager.isCaptchaRequired(player.getName())) {
|
if (captchaManager.isCaptchaRequired(player.getName())) {
|
||||||
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(true);
|
limboService.muteMessageTask(player);
|
||||||
service.send(player, MessageKey.USAGE_CAPTCHA,
|
service.send(player, MessageKey.USAGE_CAPTCHA,
|
||||||
captchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
|
captchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
|
||||||
}
|
}
|
||||||
@ -246,10 +236,6 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
// task, we schedule it in the end
|
// task, we schedule it in the end
|
||||||
// so that we can be sure, and have not to care if it might be
|
// so that we can be sure, and have not to care if it might be
|
||||||
// processed in other order.
|
// processed in other order.
|
||||||
LimboPlayer limboPlayer = limboCache.getPlayerData(name);
|
|
||||||
if (limboPlayer != null) {
|
|
||||||
limboPlayer.clearTasks();
|
|
||||||
}
|
|
||||||
syncProcessManager.processSyncPlayerLogin(player);
|
syncProcessManager.processSyncPlayerLogin(player);
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.warning("Player '" + player.getName() + "' wasn't online during login process, aborted...");
|
ConsoleLogger.warning("Player '" + player.getName() + "' wasn't online during login process, aborted...");
|
||||||
@ -260,7 +246,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
|||||||
int threshold = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD_THRESHOLD);
|
int threshold = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD_THRESHOLD);
|
||||||
String command = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD);
|
String command = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD);
|
||||||
|
|
||||||
if(threshold < 2 || command.isEmpty()) {
|
if (threshold < 2 || command.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,10 +286,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 +309,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,8 +1,8 @@
|
|||||||
package fr.xephi.authme.process.login;
|
package fr.xephi.authme.process.login;
|
||||||
|
|
||||||
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.LimboPlayer;
|
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
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;
|
||||||
@ -31,7 +31,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
private BungeeService bungeeService;
|
private BungeeService bungeeService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
@ -65,15 +65,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
|||||||
public void processPlayerLogin(Player player) {
|
public void processPlayerLogin(Player player) {
|
||||||
final String name = player.getName().toLowerCase();
|
final String name = player.getName().toLowerCase();
|
||||||
|
|
||||||
final LimboPlayer limbo = limboCache.getPlayerData(name);
|
commonService.setGroup(player, AuthGroupType.LOGGED_IN);
|
||||||
|
final LimboPlayer limbo = limboService.getLimboPlayer(name);
|
||||||
// Limbo contains the State of the Player before /login
|
// Limbo contains the State of the Player before /login
|
||||||
if (limbo != null) {
|
if (limbo != null) {
|
||||||
limboCache.restoreData(player);
|
limboService.restoreData(player);
|
||||||
limboCache.deletePlayerData(player);
|
|
||||||
// do we really need to use location from database for now?
|
|
||||||
// because LimboCache#restoreData teleport player to last location.
|
|
||||||
}
|
}
|
||||||
commonService.setGroup(player, AuthGroupType.LOGGED_IN);
|
|
||||||
|
|
||||||
if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||||
restoreInventory(player);
|
restoreInventory(player);
|
||||||
|
|||||||
@ -2,12 +2,11 @@ package fr.xephi.authme.process.logout;
|
|||||||
|
|
||||||
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.limbo.LimboCache;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.process.AsynchronousProcess;
|
import fr.xephi.authme.process.AsynchronousProcess;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.SyncProcessManager;
|
import fr.xephi.authme.process.SyncProcessManager;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@ -24,9 +23,6 @@ public class AsynchronousLogout implements AsynchronousProcess {
|
|||||||
@Inject
|
@Inject
|
||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboCache limboCache;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SyncProcessManager syncProcessManager;
|
private SyncProcessManager syncProcessManager;
|
||||||
|
|
||||||
@ -47,7 +43,6 @@ public class AsynchronousLogout implements AsynchronousProcess {
|
|||||||
database.updateQuitLoc(auth);
|
database.updateQuitLoc(auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
limboCache.addPlayerData(player);
|
|
||||||
playerCache.removePlayer(name);
|
playerCache.removePlayer(name);
|
||||||
database.setUnlogged(name);
|
database.setUnlogged(name);
|
||||||
syncProcessManager.processSyncPlayerLogout(player);
|
syncProcessManager.processSyncPlayerLogout(player);
|
||||||
|
|||||||
@ -2,17 +2,17 @@ package fr.xephi.authme.process.logout;
|
|||||||
|
|
||||||
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.limbo.LimboService;
|
||||||
import fr.xephi.authme.events.LogoutEvent;
|
import fr.xephi.authme.events.LogoutEvent;
|
||||||
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
|
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import fr.xephi.authme.service.TeleportationService;
|
||||||
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.service.BukkitService;
|
|
||||||
import fr.xephi.authme.service.TeleportationService;
|
|
||||||
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;
|
||||||
@ -34,7 +34,7 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
|||||||
private ProtocolLibService protocolLibService;
|
private ProtocolLibService protocolLibService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private SessionManager sessionManager;
|
private SessionManager sessionManager;
|
||||||
@ -53,9 +53,6 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
|||||||
protocolLibService.sendBlankInventoryPacket(player);
|
protocolLibService.sendBlankInventoryPacket(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
|
||||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
|
||||||
|
|
||||||
applyLogoutEffect(player);
|
applyLogoutEffect(player);
|
||||||
|
|
||||||
// Player is now logout... Time to fire event !
|
// Player is now logout... Time to fire event !
|
||||||
@ -71,21 +68,14 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
|||||||
teleportationService.teleportOnJoin(player);
|
teleportationService.teleportOnJoin(player);
|
||||||
|
|
||||||
// Apply Blindness effect
|
// Apply Blindness effect
|
||||||
final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
|
||||||
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||||
|
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set player's data to unauthenticated
|
// Set player's data to unauthenticated
|
||||||
|
limboService.createLimboPlayer(player, true);
|
||||||
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
player.setOp(false);
|
|
||||||
player.setAllowFlight(false);
|
|
||||||
// Remove speed
|
|
||||||
if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
|
|
||||||
&& service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
|
||||||
player.setFlySpeed(0.0f);
|
|
||||||
player.setWalkSpeed(0.0f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package fr.xephi.authme.process.quit;
|
package fr.xephi.authme.process.quit;
|
||||||
|
|
||||||
import fr.xephi.authme.data.limbo.LimboPlayerStorage;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
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;
|
||||||
|
|
||||||
@ -11,22 +10,10 @@ import javax.inject.Inject;
|
|||||||
public class ProcessSyncronousPlayerQuit implements SynchronousProcess {
|
public class ProcessSyncronousPlayerQuit implements SynchronousProcess {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboPlayerStorage limboPlayerStorage;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboCache limboCache;
|
|
||||||
|
|
||||||
public void processSyncQuit(Player player) {
|
public void processSyncQuit(Player player) {
|
||||||
if (limboCache.hasPlayerData(player.getName())) { // it mean player is not authenticated
|
limboService.restoreData(player);
|
||||||
limboCache.restoreData(player);
|
|
||||||
limboCache.removeFromCache(player);
|
|
||||||
} else {
|
|
||||||
// Save player's data, so we could retrieve it later on player next join
|
|
||||||
if (!limboPlayerStorage.hasData(player)) {
|
|
||||||
limboPlayerStorage.saveData(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player.leaveVehicle();
|
player.leaveVehicle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,13 @@ package fr.xephi.authme.process.register;
|
|||||||
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.initialization.factory.SingletonStore;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.process.AsynchronousProcess;
|
import fr.xephi.authme.process.AsynchronousProcess;
|
||||||
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
|
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
|
||||||
|
import fr.xephi.authme.process.register.executors.RegistrationParameters;
|
||||||
|
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
@ -31,6 +34,8 @@ public class AsyncRegister implements AsynchronousProcess {
|
|||||||
private CommonService service;
|
private CommonService service;
|
||||||
@Inject
|
@Inject
|
||||||
private PermissionsManager permissionsManager;
|
private PermissionsManager permissionsManager;
|
||||||
|
@Inject
|
||||||
|
private SingletonStore<RegistrationExecutor> registrationExecutorFactory;
|
||||||
|
|
||||||
AsyncRegister() {
|
AsyncRegister() {
|
||||||
}
|
}
|
||||||
@ -38,12 +43,16 @@ public class AsyncRegister implements AsynchronousProcess {
|
|||||||
/**
|
/**
|
||||||
* Performs the registration process for the given player.
|
* Performs the registration process for the given player.
|
||||||
*
|
*
|
||||||
* @param player the player to register
|
* @param variant the registration method
|
||||||
* @param executor the registration executor to perform the registration with
|
* @param parameters the parameters
|
||||||
|
* @param <P> parameters type
|
||||||
*/
|
*/
|
||||||
public void register(Player player, RegistrationExecutor executor) {
|
public <P extends RegistrationParameters> void register(RegistrationMethod<P> variant, P parameters) {
|
||||||
if (preRegisterCheck(player) && executor.isRegistrationAdmitted()) {
|
if (preRegisterCheck(parameters.getPlayer())) {
|
||||||
executeRegistration(player, executor);
|
RegistrationExecutor<P> executor = registrationExecutorFactory.getSingleton(variant.getExecutorClass());
|
||||||
|
if (executor.isRegistrationAdmitted(parameters)) {
|
||||||
|
executeRegistration(parameters, executor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,15 +75,17 @@ public class AsyncRegister implements AsynchronousProcess {
|
|||||||
/**
|
/**
|
||||||
* Executes the registration.
|
* Executes the registration.
|
||||||
*
|
*
|
||||||
* @param player the player to register
|
* @param parameters the registration parameters
|
||||||
* @param executor the executor to perform the registration process with
|
* @param executor the executor to perform the registration process with
|
||||||
|
* @param <P> registration params type
|
||||||
*/
|
*/
|
||||||
private void executeRegistration(Player player, RegistrationExecutor executor) {
|
private <P extends RegistrationParameters>
|
||||||
PlayerAuth auth = executor.buildPlayerAuth();
|
void executeRegistration(P parameters, RegistrationExecutor<P> executor) {
|
||||||
|
PlayerAuth auth = executor.buildPlayerAuth(parameters);
|
||||||
if (database.saveAuth(auth)) {
|
if (database.saveAuth(auth)) {
|
||||||
executor.executePostPersistAction();
|
executor.executePostPersistAction(parameters);
|
||||||
} else {
|
} else {
|
||||||
service.send(player, MessageKey.ERROR);
|
service.send(parameters.getPlayer(), MessageKey.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package fr.xephi.authme.process.register;
|
package fr.xephi.authme.process.register;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
import fr.xephi.authme.service.CommonService;
|
import fr.xephi.authme.service.CommonService;
|
||||||
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;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
|
|||||||
private CommonService service;
|
private CommonService service;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
private LimboService limboService;
|
||||||
|
|
||||||
ProcessSyncEmailRegister() {
|
ProcessSyncEmailRegister() {
|
||||||
}
|
}
|
||||||
@ -27,9 +27,7 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
|
|||||||
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||||
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
|
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
|
||||||
|
|
||||||
final String name = player.getName().toLowerCase();
|
limboService.replaceTasksAfterRegistration(player);
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
|
||||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
|
||||||
|
|
||||||
player.saveData();
|
player.saveData();
|
||||||
ConsoleLogger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
|
ConsoleLogger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package fr.xephi.authme.process.register;
|
package fr.xephi.authme.process.register;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
import fr.xephi.authme.message.MessageKey;
|
import fr.xephi.authme.message.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.process.SynchronousProcess;
|
import fr.xephi.authme.process.SynchronousProcess;
|
||||||
@ -10,7 +10,6 @@ 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.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
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;
|
||||||
|
|
||||||
@ -27,10 +26,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
|
|||||||
private CommonService service;
|
private CommonService service;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
@ -44,10 +40,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
|
|||||||
* @param player the player
|
* @param player the player
|
||||||
*/
|
*/
|
||||||
private void requestLogin(Player player) {
|
private void requestLogin(Player player) {
|
||||||
final String name = player.getName().toLowerCase();
|
limboService.replaceTasksAfterRegistration(player);
|
||||||
limboCache.updatePlayerData(player);
|
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
|
||||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
|
||||||
|
|
||||||
if (player.isInsideVehicle() && player.getVehicle() != null) {
|
if (player.isInsideVehicle() && player.getVehicle() != null) {
|
||||||
player.getVehicle().eject();
|
player.getVehicle().eject();
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.process.SyncProcessManager;
|
||||||
|
import fr.xephi.authme.process.login.AsynchronousLogin;
|
||||||
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import fr.xephi.authme.service.ValidationService;
|
||||||
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registration executor for registration methods where the password
|
||||||
|
* is supplied by the user.
|
||||||
|
*/
|
||||||
|
abstract class AbstractPasswordRegisterExecutor<P extends AbstractPasswordRegisterParams>
|
||||||
|
implements RegistrationExecutor<P> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of ticks to wait before running the login action when it is run synchronously.
|
||||||
|
* A small delay is necessary or the database won't return the newly saved PlayerAuth object
|
||||||
|
* and the login process thinks the user is not registered.
|
||||||
|
*/
|
||||||
|
private static final int SYNC_LOGIN_DELAY = 5;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private CommonService commonService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PasswordSecurity passwordSecurity;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SyncProcessManager syncProcessManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private AsynchronousLogin asynchronousLogin;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRegistrationAdmitted(P params) {
|
||||||
|
ValidationService.ValidationResult passwordValidation = validationService.validatePassword(
|
||||||
|
params.getPassword(), params.getPlayer().getName());
|
||||||
|
if (passwordValidation.hasError()) {
|
||||||
|
commonService.send(params.getPlayer(), passwordValidation.getMessageKey(), passwordValidation.getArgs());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlayerAuth buildPlayerAuth(P params) {
|
||||||
|
HashedPassword hashedPassword = passwordSecurity.computeHash(params.getPassword(), params.getPlayerName());
|
||||||
|
params.setHashedPassword(hashedPassword);
|
||||||
|
return createPlayerAuthObject(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the PlayerAuth object to store into the database, based on the registration parameters.
|
||||||
|
*
|
||||||
|
* @param params the parameters
|
||||||
|
* @return the PlayerAuth representing the new account to register
|
||||||
|
*/
|
||||||
|
protected abstract PlayerAuth createPlayerAuthObject(P params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the player should be automatically logged in after registration.
|
||||||
|
*
|
||||||
|
* @param params the registration parameters
|
||||||
|
* @return true if the player should be logged in, false otherwise
|
||||||
|
*/
|
||||||
|
protected boolean performLoginAfterRegister(P params) {
|
||||||
|
return !commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executePostPersistAction(P params) {
|
||||||
|
final Player player = params.getPlayer();
|
||||||
|
if (performLoginAfterRegister(params)) {
|
||||||
|
if (commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)) {
|
||||||
|
bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player));
|
||||||
|
} else {
|
||||||
|
bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syncProcessManager.processSyncPasswordRegister(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common params type for implementors of {@link AbstractPasswordRegisterExecutor}.
|
||||||
|
* Password must be supplied on creation and cannot be changed later on. The {@link HashedPassword}
|
||||||
|
* is stored on the params object for later use.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractPasswordRegisterParams extends RegistrationParameters {
|
||||||
|
|
||||||
|
private final String password;
|
||||||
|
private HashedPassword hashedPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
* @param password the password to use
|
||||||
|
*/
|
||||||
|
public AbstractPasswordRegisterParams(Player player, String password) {
|
||||||
|
super(player);
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor with no defined password. Use for registration methods which
|
||||||
|
* have no implicit password (like two factor authentication).
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
*/
|
||||||
|
public AbstractPasswordRegisterParams(Player player) {
|
||||||
|
this(player, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHashedPassword(HashedPassword hashedPassword) {
|
||||||
|
this.hashedPassword = hashedPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashedPassword getHashedPassword() {
|
||||||
|
return hashedPassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executor for password registration via API call.
|
||||||
|
*/
|
||||||
|
class ApiPasswordRegisterExecutor extends AbstractPasswordRegisterExecutor<ApiPasswordRegisterParams> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PlayerAuth createPlayerAuthObject(ApiPasswordRegisterParams params) {
|
||||||
|
return PlayerAuthBuilderHelper
|
||||||
|
.createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean performLoginAfterRegister(ApiPasswordRegisterParams params) {
|
||||||
|
return params.getLoginAfterRegister();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for {@link ApiPasswordRegisterExecutor}.
|
||||||
|
*/
|
||||||
|
public class ApiPasswordRegisterParams extends PasswordRegisterParams {
|
||||||
|
|
||||||
|
private final boolean loginAfterRegister;
|
||||||
|
|
||||||
|
protected ApiPasswordRegisterParams(Player player, String password, boolean loginAfterRegister) {
|
||||||
|
super(player, password, null);
|
||||||
|
this.loginAfterRegister = loginAfterRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a parameters object.
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
* @param password the password to register with
|
||||||
|
* @param loginAfterRegister whether the player should be logged in after registration
|
||||||
|
* @return params object with the given data
|
||||||
|
*/
|
||||||
|
public static ApiPasswordRegisterParams of(Player player, String password, boolean loginAfterRegister) {
|
||||||
|
return new ApiPasswordRegisterParams(player, password, loginAfterRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the player should be logged in after being registered, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean getLoginAfterRegister() {
|
||||||
|
return loginAfterRegister;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.mail.EmailService;
|
||||||
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.process.SyncProcessManager;
|
||||||
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
|
import fr.xephi.authme.util.RandomStringUtils;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executor for email registration: the player only provides his email address,
|
||||||
|
* to which a generated password is sent.
|
||||||
|
*/
|
||||||
|
class EmailRegisterExecutor implements RegistrationExecutor<EmailRegisterParams> {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private CommonService commonService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private EmailService emailService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SyncProcessManager syncProcessManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PasswordSecurity passwordSecurity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRegistrationAdmitted(EmailRegisterParams params) {
|
||||||
|
final int maxRegPerEmail = commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL);
|
||||||
|
if (maxRegPerEmail > 0 && !permissionsManager.hasPermission(params.getPlayer(), ALLOW_MULTIPLE_ACCOUNTS)) {
|
||||||
|
int otherAccounts = dataSource.countAuthsByEmail(params.getEmail());
|
||||||
|
if (otherAccounts >= maxRegPerEmail) {
|
||||||
|
commonService.send(params.getPlayer(), MessageKey.MAX_REGISTER_EXCEEDED,
|
||||||
|
Integer.toString(maxRegPerEmail), Integer.toString(otherAccounts), "@");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlayerAuth buildPlayerAuth(EmailRegisterParams params) {
|
||||||
|
String password = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
|
||||||
|
HashedPassword hashedPassword = passwordSecurity.computeHash(password, params.getPlayer().getName());
|
||||||
|
params.setPassword(password);
|
||||||
|
return createPlayerAuth(params.getPlayer(), hashedPassword, params.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executePostPersistAction(EmailRegisterParams params) {
|
||||||
|
Player player = params.getPlayer();
|
||||||
|
boolean couldSendMail = emailService.sendPasswordMail(
|
||||||
|
player.getName(), params.getEmail(), params.getPassword());
|
||||||
|
if (couldSendMail) {
|
||||||
|
syncProcessManager.processSyncEmailRegister(player);
|
||||||
|
} else {
|
||||||
|
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,91 +0,0 @@
|
|||||||
package fr.xephi.authme.process.register.executors;
|
|
||||||
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
|
||||||
import fr.xephi.authme.mail.EmailService;
|
|
||||||
import fr.xephi.authme.message.MessageKey;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
|
||||||
import fr.xephi.authme.process.SyncProcessManager;
|
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
|
||||||
import fr.xephi.authme.util.RandomStringUtils;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a registration executor for email registration.
|
|
||||||
*/
|
|
||||||
class EmailRegisterExecutorProvider {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PermissionsManager permissionsManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private DataSource dataSource;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private CommonService commonService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private EmailService emailService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private SyncProcessManager syncProcessManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PasswordSecurity passwordSecurity;
|
|
||||||
|
|
||||||
EmailRegisterExecutorProvider() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Registration executor implementation for email registration. */
|
|
||||||
class EmailRegisterExecutor implements RegistrationExecutor {
|
|
||||||
|
|
||||||
private final Player player;
|
|
||||||
private final String email;
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
EmailRegisterExecutor(Player player, String email) {
|
|
||||||
this.player = player;
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRegistrationAdmitted() {
|
|
||||||
final int maxRegPerEmail = commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL);
|
|
||||||
if (maxRegPerEmail > 0 && !permissionsManager.hasPermission(player, ALLOW_MULTIPLE_ACCOUNTS)) {
|
|
||||||
int otherAccounts = dataSource.countAuthsByEmail(email);
|
|
||||||
if (otherAccounts >= maxRegPerEmail) {
|
|
||||||
commonService.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerEmail),
|
|
||||||
Integer.toString(otherAccounts), "@");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PlayerAuth buildPlayerAuth() {
|
|
||||||
password = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
|
|
||||||
HashedPassword hashedPassword = passwordSecurity.computeHash(password, player.getName());
|
|
||||||
return createPlayerAuth(player, hashedPassword, email);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void executePostPersistAction() {
|
|
||||||
boolean couldSendMail = emailService.sendPasswordMail(player.getName(), email, password);
|
|
||||||
if (couldSendMail) {
|
|
||||||
syncProcessManager.processSyncEmailRegister(player);
|
|
||||||
} else {
|
|
||||||
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for email registration.
|
||||||
|
*/
|
||||||
|
public class EmailRegisterParams extends RegistrationParameters {
|
||||||
|
|
||||||
|
private final String email;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
protected EmailRegisterParams(Player player, String email) {
|
||||||
|
super(player);
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a params object for email registration.
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
* @param email the player's email
|
||||||
|
* @return params object with the given data
|
||||||
|
*/
|
||||||
|
public static EmailRegisterParams of(Player player, String email) {
|
||||||
|
return new EmailRegisterParams(player, email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the password generated for the player
|
||||||
|
*/
|
||||||
|
String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registration executor for password registration.
|
||||||
|
*/
|
||||||
|
class PasswordRegisterExecutor extends AbstractPasswordRegisterExecutor<PasswordRegisterParams> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlayerAuth createPlayerAuthObject(PasswordRegisterParams params) {
|
||||||
|
return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), params.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,155 +0,0 @@
|
|||||||
package fr.xephi.authme.process.register.executors;
|
|
||||||
|
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.message.MessageKey;
|
|
||||||
import fr.xephi.authme.process.SyncProcessManager;
|
|
||||||
import fr.xephi.authme.process.login.AsynchronousLogin;
|
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
|
||||||
import fr.xephi.authme.security.crypts.TwoFactor;
|
|
||||||
import fr.xephi.authme.service.BukkitService;
|
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.service.ValidationService;
|
|
||||||
import fr.xephi.authme.service.ValidationService.ValidationResult;
|
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides registration executors for password-based registration variants.
|
|
||||||
*/
|
|
||||||
class PasswordRegisterExecutorProvider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of ticks to wait before running the login action when it is run synchronously.
|
|
||||||
* A small delay is necessary or the database won't return the newly saved PlayerAuth object
|
|
||||||
* and the login process thinks the user is not registered.
|
|
||||||
*/
|
|
||||||
private static final int SYNC_LOGIN_DELAY = 5;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ValidationService validationService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private CommonService commonService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PasswordSecurity passwordSecurity;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private BukkitService bukkitService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private SyncProcessManager syncProcessManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AsynchronousLogin asynchronousLogin;
|
|
||||||
|
|
||||||
PasswordRegisterExecutorProvider() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Registration executor for password registration. */
|
|
||||||
class PasswordRegisterExecutor implements RegistrationExecutor {
|
|
||||||
|
|
||||||
protected final Player player;
|
|
||||||
private final String password;
|
|
||||||
private final String email;
|
|
||||||
protected HashedPassword hashedPassword;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param player the player to register
|
|
||||||
* @param password the password to register with
|
|
||||||
* @param email the email of the player (may be null)
|
|
||||||
*/
|
|
||||||
PasswordRegisterExecutor(Player player, String password, String email) {
|
|
||||||
this.player = player;
|
|
||||||
this.password = password;
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRegistrationAdmitted() {
|
|
||||||
ValidationResult passwordValidation = validationService.validatePassword(password, player.getName());
|
|
||||||
if (passwordValidation.hasError()) {
|
|
||||||
commonService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PlayerAuth buildPlayerAuth() {
|
|
||||||
hashedPassword = passwordSecurity.computeHash(password, player.getName().toLowerCase());
|
|
||||||
return createPlayerAuth(player, hashedPassword, email);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean performLoginAfterRegister() {
|
|
||||||
return !commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void executePostPersistAction() {
|
|
||||||
if (performLoginAfterRegister()) {
|
|
||||||
if (commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)) {
|
|
||||||
bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player));
|
|
||||||
} else {
|
|
||||||
bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
syncProcessManager.processSyncPasswordRegister(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Executor for password registration via API call. */
|
|
||||||
class ApiPasswordRegisterExecutor extends PasswordRegisterExecutor {
|
|
||||||
|
|
||||||
private final boolean loginAfterRegister;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param player the player to register
|
|
||||||
* @param password the password to register with
|
|
||||||
* @param loginAfterRegister whether the user should be automatically logged in after registration
|
|
||||||
*/
|
|
||||||
ApiPasswordRegisterExecutor(Player player, String password, boolean loginAfterRegister) {
|
|
||||||
super(player, password, null);
|
|
||||||
this.loginAfterRegister = loginAfterRegister;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean performLoginAfterRegister() {
|
|
||||||
return loginAfterRegister;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Executor for two factor registration. */
|
|
||||||
class TwoFactorRegisterExecutor extends PasswordRegisterExecutor {
|
|
||||||
|
|
||||||
TwoFactorRegisterExecutor(Player player) {
|
|
||||||
super(player, "", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRegistrationAdmitted() {
|
|
||||||
// nothing to check
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void executePostPersistAction() {
|
|
||||||
super.executePostPersistAction();
|
|
||||||
|
|
||||||
String qrCodeUrl = TwoFactor.getQRBarcodeURL(player.getName(), Bukkit.getIp(), hashedPassword.getHash());
|
|
||||||
commonService.send(player, MessageKey.TWO_FACTOR_CREATE, hashedPassword.getHash(), qrCodeUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for registration with a given password, and optionally an email address.
|
||||||
|
*/
|
||||||
|
public class PasswordRegisterParams extends AbstractPasswordRegisterParams {
|
||||||
|
|
||||||
|
private final String email;
|
||||||
|
|
||||||
|
protected PasswordRegisterParams(Player player, String password, String email) {
|
||||||
|
super(player, password);
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a params object.
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
* @param password the password to register with
|
||||||
|
* @param email the email of the player (may be null)
|
||||||
|
* @return params object with the given data
|
||||||
|
*/
|
||||||
|
public static PasswordRegisterParams of(Player player, String password, String email) {
|
||||||
|
return new PasswordRegisterParams(player, password, email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,6 +13,14 @@ final class PlayerAuthBuilderHelper {
|
|||||||
private PlayerAuthBuilderHelper() {
|
private PlayerAuthBuilderHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link PlayerAuth} object with the given data.
|
||||||
|
*
|
||||||
|
* @param player the player to create a PlayerAuth for
|
||||||
|
* @param hashedPassword the hashed password
|
||||||
|
* @param email the email address (nullable)
|
||||||
|
* @return the generated PlayerAuth object
|
||||||
|
*/
|
||||||
static PlayerAuth createPlayerAuth(Player player, HashedPassword hashedPassword, String email) {
|
static PlayerAuth createPlayerAuth(Player player, HashedPassword hashedPassword, String email) {
|
||||||
return PlayerAuth.builder()
|
return PlayerAuth.builder()
|
||||||
.name(player.getName().toLowerCase())
|
.name(player.getName().toLowerCase())
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import fr.xephi.authme.data.auth.PlayerAuth;
|
|||||||
/**
|
/**
|
||||||
* Performs the registration action.
|
* Performs the registration action.
|
||||||
*/
|
*/
|
||||||
public interface RegistrationExecutor {
|
public interface RegistrationExecutor<P extends RegistrationParameters> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the registration may take place. Use this method to execute
|
* Returns whether the registration may take place. Use this method to execute
|
||||||
@ -14,20 +14,24 @@ public interface RegistrationExecutor {
|
|||||||
* If this method returns {@code false}, it is expected that the executor inform
|
* If this method returns {@code false}, it is expected that the executor inform
|
||||||
* the player about the error within this method call.
|
* the player about the error within this method call.
|
||||||
*
|
*
|
||||||
|
* @param params the parameters for the registration
|
||||||
* @return true if registration may be performed, false otherwise
|
* @return true if registration may be performed, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean isRegistrationAdmitted();
|
boolean isRegistrationAdmitted(P params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the PlayerAuth object to persist into the database.
|
* Constructs the PlayerAuth object to persist into the database.
|
||||||
*
|
*
|
||||||
|
* @param params the parameters for the registration
|
||||||
* @return the player auth to register in the data source
|
* @return the player auth to register in the data source
|
||||||
*/
|
*/
|
||||||
PlayerAuth buildPlayerAuth();
|
PlayerAuth buildPlayerAuth(P params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Follow-up method called after the player auth could be added into the database.
|
* Follow-up method called after the player auth could be added into the database.
|
||||||
|
*
|
||||||
|
* @param params the parameters for the registration
|
||||||
*/
|
*/
|
||||||
void executePostPersistAction();
|
void executePostPersistAction(P params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
package fr.xephi.authme.process.register.executors;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a {@link RegistrationExecutor} for various registration methods.
|
|
||||||
*/
|
|
||||||
public class RegistrationExecutorProvider {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PasswordRegisterExecutorProvider passwordRegisterExecutorProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private EmailRegisterExecutorProvider emailRegisterExecutorProvider;
|
|
||||||
|
|
||||||
RegistrationExecutorProvider() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegistrationExecutor getPasswordRegisterExecutor(Player player, String password, String email) {
|
|
||||||
return passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, password, email);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegistrationExecutor getPasswordRegisterExecutor(Player player, String password, boolean loginAfterRegister) {
|
|
||||||
return passwordRegisterExecutorProvider.new ApiPasswordRegisterExecutor(player, password, loginAfterRegister);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegistrationExecutor getTwoFactorRegisterExecutor(Player player) {
|
|
||||||
return passwordRegisterExecutorProvider.new TwoFactorRegisterExecutor(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegistrationExecutor getEmailRegisterExecutor(Player player, String email) {
|
|
||||||
return emailRegisterExecutorProvider.new EmailRegisterExecutor(player, email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods with which a player can be registered.
|
||||||
|
* <p>
|
||||||
|
* These constants each define a different way of registering a player and define the
|
||||||
|
* {@link RegistrationParameters parameters} and {@link RegistrationExecutor executor}
|
||||||
|
* classes which perform this registration method. This is essentially a <i>typed enum</i>
|
||||||
|
* as passing a constant of this class along with a parameters object to a method can
|
||||||
|
* be restricted to the correct parameters type.
|
||||||
|
*/
|
||||||
|
public final class RegistrationMethod<P extends RegistrationParameters> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password registration.
|
||||||
|
*/
|
||||||
|
public static final RegistrationMethod<PasswordRegisterParams> PASSWORD_REGISTRATION =
|
||||||
|
new RegistrationMethod<>(PasswordRegisterExecutor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registration with two-factor authentication as login means.
|
||||||
|
*/
|
||||||
|
public static final RegistrationMethod<TwoFactorRegisterParams> TWO_FACTOR_REGISTRATION =
|
||||||
|
new RegistrationMethod<>(TwoFactorRegisterExecutor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email registration: an email address is provided, to which a generated password is sent.
|
||||||
|
*/
|
||||||
|
public static final RegistrationMethod<EmailRegisterParams> EMAIL_REGISTRATION =
|
||||||
|
new RegistrationMethod<>(EmailRegisterExecutor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API registration: player and password are provided via an API method.
|
||||||
|
*/
|
||||||
|
public static final RegistrationMethod<ApiPasswordRegisterParams> API_REGISTRATION =
|
||||||
|
new RegistrationMethod<>(ApiPasswordRegisterExecutor.class);
|
||||||
|
|
||||||
|
|
||||||
|
private final Class<? extends RegistrationExecutor<P>> executorClass;
|
||||||
|
|
||||||
|
private RegistrationMethod(Class<? extends RegistrationExecutor<P>> executorClass) {
|
||||||
|
this.executorClass = executorClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the executor class to perform the registration method
|
||||||
|
*/
|
||||||
|
public Class<? extends RegistrationExecutor<P>> getExecutorClass() {
|
||||||
|
return executorClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent of all registration parameters.
|
||||||
|
*/
|
||||||
|
public abstract class RegistrationParameters {
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param player the player to perform the registration for
|
||||||
|
*/
|
||||||
|
public RegistrationParameters(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlayerName() {
|
||||||
|
return player.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.message.MessageKey;
|
||||||
|
import fr.xephi.authme.security.crypts.TwoFactor;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executor for two-factor registration.
|
||||||
|
*/
|
||||||
|
class TwoFactorRegisterExecutor extends AbstractPasswordRegisterExecutor<TwoFactorRegisterParams> {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private CommonService commonService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRegistrationAdmitted(TwoFactorRegisterParams params) {
|
||||||
|
// nothing to check
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PlayerAuth createPlayerAuthObject(TwoFactorRegisterParams params) {
|
||||||
|
return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executePostPersistAction(TwoFactorRegisterParams params) {
|
||||||
|
super.executePostPersistAction(params);
|
||||||
|
|
||||||
|
// Note ljacqu 20170317: This two-factor registration type is only invoked when the password hash is configured
|
||||||
|
// to two-factor authentication. Therefore, the hashed password is the result of the TwoFactor EncryptionMethod
|
||||||
|
// implementation (contains the TOTP secret).
|
||||||
|
String hash = params.getHashedPassword().getHash();
|
||||||
|
String qrCodeUrl = TwoFactor.getQRBarcodeURL(params.getPlayerName(), Bukkit.getIp(), hash);
|
||||||
|
commonService.send(params.getPlayer(), MessageKey.TWO_FACTOR_CREATE, hash, qrCodeUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package fr.xephi.authme.process.register.executors;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for registration with two-factor authentication.
|
||||||
|
*/
|
||||||
|
public class TwoFactorRegisterParams extends AbstractPasswordRegisterParams {
|
||||||
|
|
||||||
|
protected TwoFactorRegisterParams(Player player) {
|
||||||
|
super(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a parameters object.
|
||||||
|
*
|
||||||
|
* @param player the player to register
|
||||||
|
* @return params object with the given player
|
||||||
|
*/
|
||||||
|
public static TwoFactorRegisterParams of(Player player) {
|
||||||
|
return new TwoFactorRegisterParams(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,19 +3,18 @@ package fr.xephi.authme.process.unregister;
|
|||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.data.auth.PlayerCache;
|
import fr.xephi.authme.data.auth.PlayerCache;
|
||||||
import fr.xephi.authme.data.limbo.LimboCache;
|
import fr.xephi.authme.data.limbo.LimboService;
|
||||||
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.permission.AuthGroupHandler;
|
import fr.xephi.authme.permission.AuthGroupHandler;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
import fr.xephi.authme.permission.AuthGroupType;
|
||||||
import fr.xephi.authme.process.AsynchronousProcess;
|
import fr.xephi.authme.process.AsynchronousProcess;
|
||||||
import fr.xephi.authme.service.CommonService;
|
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
|
import fr.xephi.authme.service.BukkitService;
|
||||||
|
import fr.xephi.authme.service.CommonService;
|
||||||
|
import fr.xephi.authme.service.TeleportationService;
|
||||||
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.service.BukkitService;
|
|
||||||
import fr.xephi.authme.service.TeleportationService;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
@ -43,10 +42,7 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
|||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboService limboService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private TeleportationService teleportationService;
|
private TeleportationService teleportationService;
|
||||||
@ -111,12 +107,10 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
|||||||
teleportationService.teleportOnJoin(player);
|
teleportationService.teleportOnJoin(player);
|
||||||
player.saveData();
|
player.saveData();
|
||||||
|
|
||||||
limboCache.deletePlayerData(player);
|
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
||||||
limboCache.addPlayerData(player);
|
limboService.createLimboPlayer(player, false);
|
||||||
|
applyBlindEffect(player);
|
||||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
});
|
||||||
limboPlayerTaskManager.registerMessageTask(name, false);
|
|
||||||
applyBlindEffect(player);
|
|
||||||
}
|
}
|
||||||
authGroupHandler.setGroup(player, AuthGroupType.UNREGISTERED);
|
authGroupHandler.setGroup(player, AuthGroupType.UNREGISTERED);
|
||||||
service.send(player, MessageKey.UNREGISTERED_SUCCESS);
|
service.send(player, MessageKey.UNREGISTERED_SUCCESS);
|
||||||
@ -124,13 +118,8 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
|||||||
|
|
||||||
private void applyBlindEffect(final Player player) {
|
private void applyBlindEffect(final Player player) {
|
||||||
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||||
final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||||
bukkitService.runTask(new Runnable() {
|
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,36 +7,36 @@ import fr.xephi.authme.security.crypts.EncryptionMethod;
|
|||||||
*/
|
*/
|
||||||
public enum HashAlgorithm {
|
public enum HashAlgorithm {
|
||||||
|
|
||||||
BCRYPT(fr.xephi.authme.security.crypts.BCRYPT.class),
|
BCRYPT(fr.xephi.authme.security.crypts.BCrypt.class),
|
||||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
BCRYPT2Y(fr.xephi.authme.security.crypts.BCrypt2y.class),
|
||||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CrazyCrypt1.class),
|
||||||
DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class),
|
DOUBLEMD5(fr.xephi.authme.security.crypts.DoubleMd5.class),
|
||||||
IPB3(fr.xephi.authme.security.crypts.IPB3.class),
|
IPB3(fr.xephi.authme.security.crypts.Ipb3.class),
|
||||||
IPB4(fr.xephi.authme.security.crypts.IPB4.class),
|
IPB4(fr.xephi.authme.security.crypts.Ipb4.class),
|
||||||
JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class),
|
JOOMLA(fr.xephi.authme.security.crypts.Joomla.class),
|
||||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
MD5(fr.xephi.authme.security.crypts.Md5.class),
|
||||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
MD5VB(fr.xephi.authme.security.crypts.Md5vB.class),
|
||||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
MYBB(fr.xephi.authme.security.crypts.MyBB.class),
|
||||||
PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
|
PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
|
||||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
|
PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
|
||||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
PHPBB(fr.xephi.authme.security.crypts.PhpBB.class),
|
||||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
PHPFUSION(fr.xephi.authme.security.crypts.PhpFusion.class),
|
||||||
@Deprecated
|
@Deprecated
|
||||||
PLAINTEXT(fr.xephi.authme.security.crypts.PLAINTEXT.class),
|
PLAINTEXT(fr.xephi.authme.security.crypts.PlainText.class),
|
||||||
ROYALAUTH(fr.xephi.authme.security.crypts.ROYALAUTH.class),
|
ROYALAUTH(fr.xephi.authme.security.crypts.RoyalAuth.class),
|
||||||
SALTED2MD5(fr.xephi.authme.security.crypts.SALTED2MD5.class),
|
SALTED2MD5(fr.xephi.authme.security.crypts.Salted2Md5.class),
|
||||||
SALTEDSHA512(fr.xephi.authme.security.crypts.SALTEDSHA512.class),
|
SALTEDSHA512(fr.xephi.authme.security.crypts.SaltedSha512.class),
|
||||||
SHA1(fr.xephi.authme.security.crypts.SHA1.class),
|
SHA1(fr.xephi.authme.security.crypts.Sha1.class),
|
||||||
SHA256(fr.xephi.authme.security.crypts.SHA256.class),
|
SHA256(fr.xephi.authme.security.crypts.Sha256.class),
|
||||||
SHA512(fr.xephi.authme.security.crypts.SHA512.class),
|
SHA512(fr.xephi.authme.security.crypts.Sha512.class),
|
||||||
SMF(fr.xephi.authme.security.crypts.SMF.class),
|
SMF(fr.xephi.authme.security.crypts.Smf.class),
|
||||||
TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class),
|
TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class),
|
||||||
WBB3(fr.xephi.authme.security.crypts.WBB3.class),
|
WBB3(fr.xephi.authme.security.crypts.Wbb3.class),
|
||||||
WBB4(fr.xephi.authme.security.crypts.WBB4.class),
|
WBB4(fr.xephi.authme.security.crypts.Wbb4.class),
|
||||||
WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class),
|
WHIRLPOOL(fr.xephi.authme.security.crypts.Whirlpool.class),
|
||||||
WORDPRESS(fr.xephi.authme.security.crypts.WORDPRESS.class),
|
WORDPRESS(fr.xephi.authme.security.crypts.Wordpress.class),
|
||||||
XAUTH(fr.xephi.authme.security.crypts.XAUTH.class),
|
XAUTH(fr.xephi.authme.security.crypts.XAuth.class),
|
||||||
XFBCRYPT(fr.xephi.authme.security.crypts.XFBCRYPT.class),
|
XFBCRYPT(fr.xephi.authme.security.crypts.XfBCrypt.class),
|
||||||
CUSTOM(null);
|
CUSTOM(null);
|
||||||
|
|
||||||
private final Class<? extends EncryptionMethod> clazz;
|
private final Class<? extends EncryptionMethod> clazz;
|
||||||
|
|||||||
@ -14,12 +14,12 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
||||||
@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting
|
@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting
|
||||||
public class BCRYPT implements EncryptionMethod {
|
public class BCrypt implements EncryptionMethod {
|
||||||
|
|
||||||
private final int bCryptLog2Rounds;
|
private final int bCryptLog2Rounds;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BCRYPT(Settings settings) {
|
public BCrypt(Settings settings) {
|
||||||
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
|
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4,7 +4,7 @@ import fr.xephi.authme.security.crypts.description.Recommendation;
|
|||||||
import fr.xephi.authme.security.crypts.description.Usage;
|
import fr.xephi.authme.security.crypts.description.Usage;
|
||||||
|
|
||||||
@Recommendation(Usage.RECOMMENDED)
|
@Recommendation(Usage.RECOMMENDED)
|
||||||
public class BCRYPT2Y extends HexSaltedMethod {
|
public class BCrypt2y extends HexSaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -6,7 +6,7 @@ import fr.xephi.authme.security.MessageDigestAlgorithm;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
public class CRAZYCRYPT1 extends UsernameSaltMethod {
|
public class CrazyCrypt1 extends UsernameSaltMethod {
|
||||||
|
|
||||||
private static final char[] CRYPTCHARS =
|
private static final char[] CRYPTCHARS =
|
||||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.security.crypts;
|
|||||||
|
|
||||||
import static fr.xephi.authme.security.HashUtils.md5;
|
import static fr.xephi.authme.security.HashUtils.md5;
|
||||||
|
|
||||||
public class DOUBLEMD5 extends UnsaltedMethod {
|
public class DoubleMd5 extends UnsaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password) {
|
public String computeHash(String password) {
|
||||||
@ -10,7 +10,7 @@ import static fr.xephi.authme.security.HashUtils.md5;
|
|||||||
|
|
||||||
@Recommendation(Usage.ACCEPTABLE)
|
@Recommendation(Usage.ACCEPTABLE)
|
||||||
@HasSalt(value = SaltType.TEXT, length = 5)
|
@HasSalt(value = SaltType.TEXT, length = 5)
|
||||||
public class IPB3 extends SeparateSaltMethod {
|
public class Ipb3 extends SeparateSaltMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -11,15 +11,15 @@ import fr.xephi.authme.util.StringUtils;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation for IPB4 (Invision Power Board 4).
|
* Implementation for Ipb4 (Invision Power Board 4).
|
||||||
* <p>
|
* <p>
|
||||||
* The hash uses standard BCrypt with 13 as log<sub>2</sub> number of rounds. Additionally,
|
* The hash uses standard BCrypt with 13 as log<sub>2</sub> number of rounds. Additionally,
|
||||||
* IPB4 requires that the salt be stored additionally in the column "members_pass_hash"
|
* Ipb4 requires that the salt be stored additionally in the column "members_pass_hash"
|
||||||
* (even though BCrypt hashes already have the salt in the result).
|
* (even though BCrypt hashes already have the salt in the result).
|
||||||
*/
|
*/
|
||||||
@Recommendation(Usage.DOES_NOT_WORK)
|
@Recommendation(Usage.DOES_NOT_WORK)
|
||||||
@HasSalt(value = SaltType.TEXT, length = 22)
|
@HasSalt(value = SaltType.TEXT, length = 22)
|
||||||
public class IPB4 implements EncryptionMethod {
|
public class Ipb4 implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -5,7 +5,7 @@ import fr.xephi.authme.security.crypts.description.Recommendation;
|
|||||||
import fr.xephi.authme.security.crypts.description.Usage;
|
import fr.xephi.authme.security.crypts.description.Usage;
|
||||||
|
|
||||||
@Recommendation(Usage.ACCEPTABLE)
|
@Recommendation(Usage.ACCEPTABLE)
|
||||||
public class JOOMLA extends HexSaltedMethod {
|
public class Joomla extends HexSaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.security.crypts;
|
|||||||
|
|
||||||
import fr.xephi.authme.security.HashUtils;
|
import fr.xephi.authme.security.HashUtils;
|
||||||
|
|
||||||
public class MD5 extends UnsaltedMethod {
|
public class Md5 extends UnsaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password) {
|
public String computeHash(String password) {
|
||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.security.crypts;
|
|||||||
|
|
||||||
import static fr.xephi.authme.security.HashUtils.md5;
|
import static fr.xephi.authme.security.HashUtils.md5;
|
||||||
|
|
||||||
public class MD5VB extends HexSaltedMethod {
|
public class Md5vB extends HexSaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -10,7 +10,7 @@ import static fr.xephi.authme.security.HashUtils.md5;
|
|||||||
|
|
||||||
@Recommendation(Usage.ACCEPTABLE)
|
@Recommendation(Usage.ACCEPTABLE)
|
||||||
@HasSalt(value = SaltType.TEXT, length = 8)
|
@HasSalt(value = SaltType.TEXT, length = 8)
|
||||||
public class MYBB extends SeparateSaltMethod {
|
public class MyBB extends SeparateSaltMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -9,7 +9,7 @@ import java.security.MessageDigest;
|
|||||||
/**
|
/**
|
||||||
* @author stefano
|
* @author stefano
|
||||||
*/
|
*/
|
||||||
public class PHPBB extends HexSaltedMethod {
|
public class PhpBB extends HexSaltedMethod {
|
||||||
|
|
||||||
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user