mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-09-07 12:48:03 +02:00
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="allowMissingThrowsTags" value="true"/>
|
||||
<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"/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
@ -159,6 +159,8 @@
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="ignore|ignored"/>
|
||||
</module>
|
||||
<module name="MissingOverride"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
</module>
|
||||
<module name="FileTabCharacter"/>
|
||||
</module>
|
||||
|
@ -25,4 +25,6 @@ exclude_paths:
|
||||
- 'src/main/java/fr/xephi/authme/mail/OAuth2SaslClient.java'
|
||||
- 'src/main/java/fr/xephi/authme/mail/OAuth2SaslClientFactory.java'
|
||||
- 'src/main/java/fr/xephi/authme/security/crypts/BCryptService.java'
|
||||
- 'src/main/java/fr/xephi/authme/security/crypts/PHPBB.java'
|
||||
- 'src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java'
|
||||
- 'src/main/java/fr/xephi/authme/security/crypts/WORDPRESS.java'
|
||||
|
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
|
||||
hs_err_pid*
|
||||
|
||||
|
||||
# Mac OS
|
||||
.DS_Store
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
||||
|
14
README.md
14
README.md
@ -19,20 +19,14 @@
|
||||
- Project status:
|
||||
- Dependencies: [![Dependencies status](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d/badge.svg)](https://www.versioneye.com/user/projects/57b182e8d6ffcd0032d7cf2d)
|
||||
- Test coverage: [![Coverage status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
||||
- Code climate: [![Code Climate](https://codeclimate.com/github/AuthMe/AuthMeReloaded/badges/gpa.svg)](https://codeclimate.com/github/AuthMe/AuthMeReloaded)
|
||||
|
||||
- Development resources:
|
||||
- <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">JavaDocs</a>
|
||||
- <a href="http://ci.xephi.fr/plugin/repository/everything/">Maven Repository</a>
|
||||
|
||||
#####Statistics:
|
||||
|
||||
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">
|
||||
- Statistics:
|
||||
- bStats: [AuthMe on bstats.org](https://bstats.org/plugin/bukkit/AuthMe)
|
||||
|
||||
<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>WordPress: WORDPRESS</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>Fully compatible with Citizens2, CombatTag, CombatTagPlus!</strong></li>
|
||||
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
|
||||
|
@ -73,17 +73,6 @@ ExternalBoardOptions:
|
||||
phpbbActivatedGroupId: 2
|
||||
# Wordpress prefix defined during WordPress installation
|
||||
wordpressTablePrefix: 'wp_'
|
||||
Converter:
|
||||
Rakamak:
|
||||
# Rakamak file name
|
||||
fileName: 'users.rak'
|
||||
# Rakamak use IP?
|
||||
useIP: false
|
||||
# Rakamak IP file name
|
||||
ipFileName: 'UsersIp.rak'
|
||||
CrazyLogin:
|
||||
# CrazyLogin database file name
|
||||
fileName: 'accounts.db'
|
||||
settings:
|
||||
sessions:
|
||||
# Do you want to enable the session feature?
|
||||
@ -452,6 +441,23 @@ Security:
|
||||
# Seconds a user has to wait for before a password recovery mail may be sent again
|
||||
# This prevents an attacker from abusing AuthMe's email feature.
|
||||
cooldown: 60
|
||||
# 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:
|
||||
# Enable or disable automatic backup
|
||||
ActivateBackup: false
|
||||
@ -461,6 +467,17 @@ BackupSystem:
|
||||
OnServerStop: true
|
||||
# Windows only mysql installation Path
|
||||
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
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- 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
|
||||
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 |
|
||||
---- | -------- | ---------: | ------
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
[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" />
|
||||
@ -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" />
|
||||
[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.TaskCloser;
|
||||
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.EntityListener;
|
||||
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.permission.PermissionsManager;
|
||||
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.BukkitService;
|
||||
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.task.CleanupTask;
|
||||
import fr.xephi.authme.task.purge.PurgeService;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -195,12 +197,17 @@ public class AuthMe extends JavaPlugin {
|
||||
ConsoleLogger.setLogger(getLogger());
|
||||
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
|
||||
getDataFolder().mkdir();
|
||||
|
||||
// Create injector, provide elements from the Bukkit environment and register providers
|
||||
injector = new InjectorBuilder()
|
||||
.addHandlers(new FactoryDependencyHandler())
|
||||
.addHandlers(new FactoryDependencyHandler(), new SingletonStoreDependencyHandler())
|
||||
.addDefaultHandlers("fr.xephi.authme")
|
||||
.create();
|
||||
injector.register(AuthMe.class, this);
|
||||
@ -220,7 +227,7 @@ public class AuthMe extends JavaPlugin {
|
||||
instantiateServices(injector);
|
||||
|
||||
// Convert deprecated PLAINTEXT hash entries
|
||||
MigrationService.changePlainTextToSha256(settings, database, new SHA256());
|
||||
MigrationService.changePlainTextToSha256(settings, database, new Sha256());
|
||||
|
||||
// TODO: does this still make sense? -sgdc3
|
||||
// If the server is empty (fresh start) just set all the players as unlogged
|
||||
|
@ -23,6 +23,7 @@ import javax.inject.Inject;
|
||||
* @deprecated Use {@link NewAPI}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore
|
||||
public class API {
|
||||
|
||||
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.datasource.DataSource;
|
||||
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.crypts.HashedPassword;
|
||||
import fr.xephi.authme.service.PluginHookService;
|
||||
@ -24,6 +25,7 @@ import java.util.List;
|
||||
* NewAPI authmeApi = AuthMe.getApi();
|
||||
* </code>
|
||||
*/
|
||||
@SuppressWarnings({"checkstyle:AbbreviationAsWordInName"}) // Justification: Class name cannot be changed anymore
|
||||
public class NewAPI {
|
||||
|
||||
private static NewAPI singleton;
|
||||
@ -34,15 +36,13 @@ public class NewAPI {
|
||||
private final Management management;
|
||||
private final ValidationService validationService;
|
||||
private final PlayerCache playerCache;
|
||||
private final RegistrationExecutorProvider registrationExecutorProvider;
|
||||
|
||||
/*
|
||||
* Constructor for NewAPI.
|
||||
*/
|
||||
@Inject
|
||||
NewAPI(AuthMe plugin, PluginHookService pluginHookService, DataSource dataSource, PasswordSecurity passwordSecurity,
|
||||
Management management, ValidationService validationService, PlayerCache playerCache,
|
||||
RegistrationExecutorProvider registrationExecutorProvider) {
|
||||
Management management, ValidationService validationService, PlayerCache playerCache) {
|
||||
this.plugin = plugin;
|
||||
this.pluginHookService = pluginHookService;
|
||||
this.dataSource = dataSource;
|
||||
@ -50,7 +50,6 @@ public class NewAPI {
|
||||
this.management = management;
|
||||
this.validationService = validationService;
|
||||
this.playerCache = playerCache;
|
||||
this.registrationExecutorProvider = registrationExecutorProvider;
|
||||
NewAPI.singleton = this;
|
||||
}
|
||||
|
||||
@ -203,8 +202,8 @@ public class NewAPI {
|
||||
* @param autoLogin Should the player be authenticated automatically after the registration?
|
||||
*/
|
||||
public void forceRegister(Player player, String password, boolean autoLogin) {
|
||||
management.performRegister(player,
|
||||
registrationExecutorProvider.getPasswordRegisterExecutor(player, password, autoLogin));
|
||||
management.performRegister(RegistrationMethod.API_REGISTRATION,
|
||||
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
|
||||
* the child defines.
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:FinalClass") // Justification: class is mocked in multiple tests
|
||||
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.RoyalAuthConverter;
|
||||
import fr.xephi.authme.datasource.converter.SqliteToSql;
|
||||
import fr.xephi.authme.datasource.converter.vAuthConverter;
|
||||
import fr.xephi.authme.datasource.converter.xAuthConverter;
|
||||
import fr.xephi.authme.datasource.converter.VAuthConverter;
|
||||
import fr.xephi.authme.datasource.converter.XAuthConverter;
|
||||
import fr.xephi.authme.initialization.factory.Factory;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
@ -78,11 +78,11 @@ public class ConverterCommand implements ExecutableCommand {
|
||||
*/
|
||||
private static Map<String, Class<? extends Converter>> getConverters() {
|
||||
return ImmutableMap.<String, Class<? extends Converter>>builder()
|
||||
.put("xauth", xAuthConverter.class)
|
||||
.put("xauth", XAuthConverter.class)
|
||||
.put("crazylogin", CrazyLoginConverter.class)
|
||||
.put("rakamak", RakamakConverter.class)
|
||||
.put("royalauth", RoyalAuthConverter.class)
|
||||
.put("vauth", vAuthConverter.class)
|
||||
.put("vauth", VAuthConverter.class)
|
||||
.put("sqlitetosql", SqliteToSql.class)
|
||||
.put("mysqltosqlite", MySqlToSqlite.class)
|
||||
.build();
|
||||
|
@ -1,9 +1,8 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
@ -38,9 +37,6 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Override
|
||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||
// Get the player name and password
|
||||
@ -83,7 +79,6 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
limboCache.restoreData(player);
|
||||
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.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -44,8 +44,7 @@ public class ReloadCommand implements ExecutableCommand {
|
||||
ConsoleLogger.setLoggingOptions(settings);
|
||||
// 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())) {
|
||||
ConsoleLogger.info("Note: cannot change database type during /authme reload");
|
||||
sender.sendMessage("Note: cannot change database type during /authme reload");
|
||||
Utils.logAndSendMessage(sender, "Note: cannot change database type during /authme reload");
|
||||
}
|
||||
performReloadOnServices();
|
||||
commonService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
||||
@ -57,14 +56,10 @@ public class ReloadCommand implements ExecutableCommand {
|
||||
}
|
||||
|
||||
private void performReloadOnServices() {
|
||||
Collection<Reloadable> reloadables = injector.retrieveAllOfType(Reloadable.class);
|
||||
for (Reloadable reloadable : reloadables) {
|
||||
reloadable.reload();
|
||||
}
|
||||
injector.retrieveAllOfType(Reloadable.class)
|
||||
.forEach(r -> r.reload());
|
||||
|
||||
Collection<SettingsDependent> settingsDependents = injector.retrieveAllOfType(SettingsDependent.class);
|
||||
for (SettingsDependent dependent : settingsDependents) {
|
||||
dependent.reload(settings);
|
||||
}
|
||||
injector.retrieveAllOfType(SettingsDependent.class)
|
||||
.forEach(s -> s.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 javax.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Debug command main.
|
||||
@ -19,8 +19,9 @@ public class DebugCommand implements ExecutableCommand {
|
||||
@Inject
|
||||
private Factory<DebugSection> debugSectionFactory;
|
||||
|
||||
private Set<Class<? extends DebugSection>> sectionClasses =
|
||||
ImmutableSet.of(PermissionGroups.class, TestEmailSender.class);
|
||||
private Set<Class<? extends DebugSection>> sectionClasses = ImmutableSet.of(PermissionGroups.class,
|
||||
DataStatistics.class, CountryLookup.class, PlayerAuthViewer.class, LimboPlayerViewer.class, CountryLookup.class,
|
||||
HasPermissionChecker.class, TestEmailSender.class);
|
||||
|
||||
private Map<String, DebugSection> sections;
|
||||
|
||||
@ -46,7 +47,7 @@ public class DebugCommand implements ExecutableCommand {
|
||||
// Lazy getter
|
||||
private Map<String, DebugSection> getSections() {
|
||||
if (sections == null) {
|
||||
Map<String, DebugSection> sections = new HashMap<>();
|
||||
Map<String, DebugSection> sections = new TreeMap<>();
|
||||
for (Class<? extends DebugSection> sectionClass : sectionClasses) {
|
||||
DebugSection section = debugSectionFactory.newInstance(sectionClass);
|
||||
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
|
||||
public void execute(CommandSender sender, List<String> arguments) {
|
||||
if (!sendMailSSL.hasAllInformation()) {
|
||||
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml " +
|
||||
"for sending emails. Please check your config.yml");
|
||||
sender.sendMessage(ChatColor.RED + "You haven't set all required configurations in config.yml "
|
||||
+ "for sending emails. Please check your config.yml");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -69,7 +69,8 @@ class TestEmailSender implements DebugSection {
|
||||
}
|
||||
String email = auth.getEmail();
|
||||
if (email == null || "your@email.com".equals(email)) {
|
||||
sender.sendMessage(ChatColor.RED + "No email set for your account! Please use /authme debug mail <email>");
|
||||
sender.sendMessage(ChatColor.RED + "No email set for your account!"
|
||||
+ " Please use /authme debug mail <email>");
|
||||
return null;
|
||||
}
|
||||
return email;
|
||||
|
@ -3,8 +3,7 @@ package fr.xephi.authme.command.executable.captcha;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.data.CaptchaManager;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -24,7 +23,7 @@ public class CaptchaCommand extends PlayerCommand {
|
||||
private CommonService commonService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private LimboService limboService;
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
@ -44,7 +43,7 @@ public class CaptchaCommand extends PlayerCommand {
|
||||
if (isCorrectCode) {
|
||||
commonService.send(player, MessageKey.CAPTCHA_SUCCESS);
|
||||
commonService.send(player, MessageKey.LOGIN_MESSAGE);
|
||||
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(false);
|
||||
limboService.unmuteMessageTask(player);
|
||||
} else {
|
||||
String newCode = captchaManager.generateCode(player.getName());
|
||||
commonService.send(player, MessageKey.CAPTCHA_WRONG_ERROR, newCode);
|
||||
|
@ -24,7 +24,7 @@ public class ShowEmailCommand extends PlayerCommand {
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
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());
|
||||
} else {
|
||||
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.register.RegisterSecondaryArgument;
|
||||
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.service.CommonService;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
@ -42,15 +45,12 @@ public class RegisterCommand extends PlayerCommand {
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@Inject
|
||||
private RegistrationExecutorProvider registrationExecutorProvider;
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
||||
//for two factor auth we don't need to check the usage
|
||||
management.performRegister(player,
|
||||
registrationExecutorProvider.getTwoFactorRegisterExecutor(player));
|
||||
management.performRegister(RegistrationMethod.TWO_FACTOR_REGISTRATION,
|
||||
TwoFactorRegisterParams.of(player));
|
||||
return;
|
||||
} else if (arguments.size() < 1) {
|
||||
commonService.send(player, MessageKey.USAGE_REGISTER);
|
||||
@ -82,8 +82,8 @@ public class RegisterCommand extends PlayerCommand {
|
||||
final String password = arguments.get(0);
|
||||
final String email = getEmailIfAvailable(arguments);
|
||||
|
||||
management.performRegister(
|
||||
player, registrationExecutorProvider.getPasswordRegisterExecutor(player, password, email));
|
||||
management.performRegister(RegistrationMethod.PASSWORD_REGISTRATION,
|
||||
PasswordRegisterParams.of(player, password, email));
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +138,8 @@ public class RegisterCommand extends PlayerCommand {
|
||||
if (!validationService.validateEmail(email)) {
|
||||
commonService.send(player, MessageKey.INVALID_EMAIL);
|
||||
} 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.
|
||||
*/
|
||||
public void clearTasks() {
|
||||
if (messageTask != null) {
|
||||
messageTask.cancel();
|
||||
}
|
||||
messageTask = null;
|
||||
if (timeoutTask != null) {
|
||||
timeoutTask.cancel();
|
||||
}
|
||||
timeoutTask = null;
|
||||
setMessageTask(null);
|
||||
setTimeoutTask(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.
|
||||
*/
|
||||
// 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 String NAME;
|
||||
|
@ -7,7 +7,7 @@ import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.HashAlgorithm;
|
||||
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.properties.DatabaseSettings;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
@ -45,7 +45,10 @@ public class MySQL implements DataSource {
|
||||
private HikariDataSource ds;
|
||||
|
||||
private String phpBbPrefix;
|
||||
private String IPBPrefix;
|
||||
private int phpBbGroup;
|
||||
private int IPBGroup;
|
||||
private int XFGroup;
|
||||
private String wordpressPrefix;
|
||||
|
||||
public MySQL(Settings settings) throws ClassNotFoundException, SQLException {
|
||||
@ -96,6 +99,9 @@ public class MySQL implements DataSource {
|
||||
this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
|
||||
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
|
||||
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.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
|
||||
if (poolSize == -1) {
|
||||
@ -286,7 +292,7 @@ public class MySQL implements DataSource {
|
||||
if (rs.next()) {
|
||||
Blob blob = rs.getBlob("data");
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (hashAlgorithm == HashAlgorithm.PHPBB) {
|
||||
if (hashAlgorithm == HashAlgorithm.IPB4){
|
||||
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 + "=?;";
|
||||
pst = con.prepareStatement(sql);
|
||||
pst.setString(1, auth.getNickname());
|
||||
@ -477,19 +514,53 @@ public class MySQL implements DataSource {
|
||||
pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;");
|
||||
pst.setString(1, auth.getNickname());
|
||||
rs = pst.executeQuery();
|
||||
if (rs.next()) {
|
||||
if (rs.next()) {
|
||||
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 (?,?,?)";
|
||||
pst2 = con.prepareStatement(sql);
|
||||
pst2.setInt(1, id);
|
||||
pst2.setString(2, XFBCRYPT.SCHEME_CLASS);
|
||||
String serializedHash = XFBCRYPT.serializeHash(auth.getPassword().getHash());
|
||||
pst2.setString(2, XfBCrypt.SCHEME_CLASS);
|
||||
String serializedHash = XfBCrypt.serializeHash(auth.getPassword().getHash());
|
||||
byte[] bytes = serializedHash.getBytes();
|
||||
Blob blob = con.createBlob();
|
||||
blob.setBytes(1, bytes);
|
||||
pst2.setBlob(3, blob);
|
||||
pst2.executeUpdate();
|
||||
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();
|
||||
pst.close();
|
||||
@ -538,7 +609,7 @@ public class MySQL implements DataSource {
|
||||
// Insert password in the correct table
|
||||
sql = "UPDATE xf_user_authenticate SET data=? WHERE " + col.ID + "=?;";
|
||||
PreparedStatement pst2 = con.prepareStatement(sql);
|
||||
String serializedHash = XFBCRYPT.serializeHash(password.getHash());
|
||||
String serializedHash = XfBCrypt.serializeHash(password.getHash());
|
||||
byte[] bytes = serializedHash.getBytes();
|
||||
Blob blob = con.createBlob();
|
||||
blob.setBytes(1, bytes);
|
||||
@ -549,7 +620,7 @@ public class MySQL implements DataSource {
|
||||
// ...
|
||||
sql = "UPDATE xf_user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;";
|
||||
pst2 = con.prepareStatement(sql);
|
||||
pst2.setString(1, XFBCRYPT.SCHEME_CLASS);
|
||||
pst2.setString(1, XfBCrypt.SCHEME_CLASS);
|
||||
pst2.setInt(2, id);
|
||||
pst2.executeUpdate();
|
||||
pst2.close();
|
||||
@ -824,7 +895,7 @@ public class MySQL implements DataSource {
|
||||
if (rs2.next()) {
|
||||
Blob blob = rs2.getBlob("data");
|
||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
||||
pAuth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes)));
|
||||
}
|
||||
rs2.close();
|
||||
}
|
||||
@ -856,7 +927,7 @@ public class MySQL implements DataSource {
|
||||
if (rs2.next()) {
|
||||
Blob blob = rs2.getBlob("data");
|
||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
||||
pAuth.setPassword(new HashedPassword(XfBCrypt.getHashFromBlob(bytes)));
|
||||
}
|
||||
rs2.close();
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
@ -40,19 +41,17 @@ public class RakamakConverter implements Converter {
|
||||
@Override
|
||||
// TODO ljacqu 20151229: Restructure this into smaller portions
|
||||
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 ipFileName = settings.getProperty(ConverterSettings.RAKAMAK_IP_FILE_NAME);
|
||||
File source = new File(pluginFolder, fileName);
|
||||
File ipfiles = new File(pluginFolder, ipFileName);
|
||||
HashMap<String, String> playerIP = new HashMap<>();
|
||||
HashMap<String, HashedPassword> playerPSW = new HashMap<>();
|
||||
File ipFiles = new File(pluginFolder, ipFileName);
|
||||
Map<String, String> playerIP = new HashMap<>();
|
||||
Map<String, HashedPassword> playerPassword = new HashMap<>();
|
||||
try {
|
||||
BufferedReader users;
|
||||
BufferedReader ipFile;
|
||||
ipFile = new BufferedReader(new FileReader(ipfiles));
|
||||
BufferedReader ipFile = new BufferedReader(new FileReader(ipFiles));
|
||||
String line;
|
||||
if (useIP) {
|
||||
if (useIp) {
|
||||
String tempLine;
|
||||
while ((tempLine = ipFile.readLine()) != null) {
|
||||
if (tempLine.contains("=")) {
|
||||
@ -63,20 +62,20 @@ public class RakamakConverter implements Converter {
|
||||
}
|
||||
ipFile.close();
|
||||
|
||||
users = new BufferedReader(new FileReader(source));
|
||||
BufferedReader users = new BufferedReader(new FileReader(source));
|
||||
while ((line = users.readLine()) != null) {
|
||||
if (line.contains("=")) {
|
||||
String[] arguments = line.split("=");
|
||||
HashedPassword hashedPassword = passwordSecurity.computeHash(arguments[1], arguments[0]);
|
||||
playerPSW.put(arguments[0], hashedPassword);
|
||||
playerPassword.put(arguments[0], hashedPassword);
|
||||
|
||||
}
|
||||
}
|
||||
users.close();
|
||||
for (Entry<String, HashedPassword> m : playerPSW.entrySet()) {
|
||||
for (Entry<String, HashedPassword> m : playerPassword.entrySet()) {
|
||||
String playerName = m.getKey();
|
||||
HashedPassword psw = playerPSW.get(playerName);
|
||||
String ip = useIP ? playerIP.get(playerName) : "127.0.0.1";
|
||||
HashedPassword psw = playerPassword.get(playerName);
|
||||
String ip = useIp ? playerIP.get(playerName) : "127.0.0.1";
|
||||
PlayerAuth auth = PlayerAuth.builder()
|
||||
.name(playerName)
|
||||
.realName(playerName)
|
||||
|
@ -16,13 +16,13 @@ import java.util.UUID;
|
||||
|
||||
import static fr.xephi.authme.util.FileUtils.makePath;
|
||||
|
||||
public class vAuthConverter implements Converter {
|
||||
public class VAuthConverter implements Converter {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final File vAuthPasswordsFile;
|
||||
|
||||
@Inject
|
||||
vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
||||
VAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
||||
vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
|
||||
this.dataSource = dataSource;
|
||||
}
|
@ -21,7 +21,7 @@ import java.util.List;
|
||||
|
||||
import static fr.xephi.authme.util.FileUtils.makePath;
|
||||
|
||||
public class xAuthConverter implements Converter {
|
||||
public class XAuthConverter implements Converter {
|
||||
|
||||
@Inject
|
||||
@DataFolder
|
||||
@ -31,7 +31,7 @@ public class xAuthConverter implements Converter {
|
||||
@Inject
|
||||
private PluginManager pluginManager;
|
||||
|
||||
xAuthConverter() {
|
||||
XAuthConverter() {
|
||||
}
|
||||
|
||||
@Override
|
@ -2,15 +2,14 @@ package fr.xephi.authme.initialization;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayerStorage;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.service.PluginHookService;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.SpawnLoader;
|
||||
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.entity.Player;
|
||||
|
||||
@ -28,17 +27,15 @@ public class OnShutdownPlayerSaver {
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
@Inject
|
||||
private DataSource dataSource;
|
||||
@Inject
|
||||
private LimboPlayerStorage limboPlayerStorage;
|
||||
@Inject
|
||||
private SpawnLoader spawnLoader;
|
||||
@Inject
|
||||
private PluginHookService pluginHookService;
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
@Inject
|
||||
private LimboService limboService;
|
||||
|
||||
OnShutdownPlayerSaver() {
|
||||
}
|
||||
@ -57,9 +54,8 @@ public class OnShutdownPlayerSaver {
|
||||
if (pluginHookService.isNpc(player) || validationService.isUnrestricted(name)) {
|
||||
return;
|
||||
}
|
||||
if (limboCache.hasPlayerData(name)) {
|
||||
limboCache.restoreData(player);
|
||||
limboCache.removeFromCache(player);
|
||||
if (limboService.hasLimboPlayer(name)) {
|
||||
limboService.restoreData(player);
|
||||
} else {
|
||||
saveLoggedinPlayer(player);
|
||||
}
|
||||
@ -75,9 +71,5 @@ public class OnShutdownPlayerSaver {
|
||||
.location(loc).build();
|
||||
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() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends bstats metrics.
|
||||
*
|
||||
* @param plugin the plugin instance
|
||||
* @param settings the settings
|
||||
*/
|
||||
public static void sendMetrics(AuthMe plugin, Settings settings) {
|
||||
final Metrics metrics = new Metrics(plugin);
|
||||
|
||||
|
@ -16,8 +16,8 @@ public class FactoryDependencyHandler implements DependencyHandler {
|
||||
if (dependencyDescription.getType() == Factory.class) {
|
||||
Class<?> genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType());
|
||||
if (genericType == null) {
|
||||
throw new IllegalStateException("Factory fields must have concrete generic type. " +
|
||||
"Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
||||
throw new IllegalStateException("Factory fields must have concrete generic type. "
|
||||
+ "Cannot get generic type for field in '" + context.getMappedClass() + "'");
|
||||
}
|
||||
|
||||
return new FactoryImpl<>(genericType, context.getInjector());
|
||||
|
@ -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
|
||||
*
|
||||
* @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) {
|
||||
final Player player = event.getPlayer();
|
||||
|
@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package fr.xephi.authme.listener.protocollib;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
@ -46,7 +47,7 @@ class InventoryPacketAdapter extends PacketAdapter {
|
||||
private static final int MAIN_SIZE = 27;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
|
||||
|
||||
class TabCompletePacketAdapter extends PacketAdapter {
|
||||
|
||||
public TabCompletePacketAdapter(AuthMe plugin) {
|
||||
TabCompletePacketAdapter(AuthMe plugin) {
|
||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package fr.xephi.authme.mail;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.output.LogLevel;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.apache.commons.mail.EmailConstants;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
@ -56,6 +58,9 @@ public class SendMailSSL {
|
||||
email.setFrom(senderMail, senderName);
|
||||
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
||||
email.setAuthentication(settings.getProperty(EmailSettings.MAIL_ACCOUNT), mailPassword);
|
||||
if (settings.getProperty(PluginSettings.LOG_LEVEL).includes(LogLevel.DEBUG)) {
|
||||
email.setDebug(true);
|
||||
}
|
||||
|
||||
setPropertiesForPort(email, port);
|
||||
return email;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package fr.xephi.authme.permission;
|
||||
|
||||
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.LimboService;
|
||||
import fr.xephi.authme.initialization.Reloadable;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
@ -33,7 +33,7 @@ public class AuthGroupHandler implements Reloadable {
|
||||
private Settings settings;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private LimboService limboService;
|
||||
|
||||
private String unregisteredGroup;
|
||||
private String registeredGroup;
|
||||
@ -53,7 +53,7 @@ public class AuthGroupHandler implements Reloadable {
|
||||
}
|
||||
|
||||
String primaryGroup = Optional
|
||||
.ofNullable(limboCache.getPlayerData(player.getName()))
|
||||
.ofNullable(limboService.getLimboPlayer(player.getName()))
|
||||
.map(LimboPlayer::getGroup)
|
||||
.orElse("");
|
||||
|
||||
|
@ -31,7 +31,8 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
||||
|
||||
@Override
|
||||
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
|
||||
@ -46,17 +47,19 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
public List<String> getGroups(Player player) {
|
||||
List<String> groups = new ArrayList<String>();
|
||||
List<String> groups = new ArrayList<>();
|
||||
for (Group group : permissionsBukkitInstance.getGroups(player.getUniqueId())) {
|
||||
groups.add(group.getName());
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ public class ZPermissionsHandler implements PermissionHandler {
|
||||
|
||||
@Override
|
||||
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
|
||||
@ -41,20 +42,23 @@ public class ZPermissionsHandler implements PermissionHandler {
|
||||
@Override
|
||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||
Map<String, Boolean> perms = zPermissionsService.getPlayerPermissions(null, null, name);
|
||||
if (perms.containsKey(node.getNode()))
|
||||
if (perms.containsKey(node.getNode())) {
|
||||
return perms.get(node.getNode());
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
|
@ -8,7 +8,8 @@ import fr.xephi.authme.process.login.AsynchronousLogin;
|
||||
import fr.xephi.authme.process.logout.AsynchronousLogout;
|
||||
import fr.xephi.authme.process.quit.AsynchronousQuit;
|
||||
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.service.BukkitService;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -60,8 +61,8 @@ public class Management {
|
||||
runTask(() -> asynchronousLogout.logout(player));
|
||||
}
|
||||
|
||||
public void performRegister(Player player, RegistrationExecutor registrationExecutor) {
|
||||
runTask(() -> asyncRegister.register(player, registrationExecutor));
|
||||
public <P extends RegistrationParameters> void performRegister(RegistrationMethod<P> variant, P parameters) {
|
||||
runTask(() -> asyncRegister.register(variant, parameters));
|
||||
}
|
||||
|
||||
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.auth.PlayerAuth;
|
||||
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.events.ProtectInventoryEvent;
|
||||
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.CommonService;
|
||||
import fr.xephi.authme.service.PluginHookService;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
import fr.xephi.authme.settings.commandconfig.CommandManager;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Server;
|
||||
@ -51,7 +51,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private LimboService limboService;
|
||||
|
||||
@Inject
|
||||
private SessionManager sessionManager;
|
||||
@ -62,15 +62,15 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
|
||||
@Inject
|
||||
private AsynchronousLogin asynchronousLogin;
|
||||
|
||||
@Inject
|
||||
private CommandManager commandManager;
|
||||
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
AsynchronousJoin() {
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
pluginHookService.setEssentialsSocialSpyStatus(player, false);
|
||||
}
|
||||
|
||||
if (isNameRestricted(name, ip, player.getAddress().getHostName())) {
|
||||
if (!validationService.fulfillsNameRestrictions(player)) {
|
||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -111,7 +111,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
final boolean isAuthAvailable = database.isAuthAvailable(name);
|
||||
|
||||
if (isAuthAvailable) {
|
||||
limboCache.addPlayerData(player);
|
||||
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||
|
||||
// Protect inventory
|
||||
@ -141,10 +140,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not Registered. Delete old data, load default one.
|
||||
limboCache.deletePlayerData(player);
|
||||
limboCache.addPlayerData(player);
|
||||
|
||||
// Groups logic
|
||||
service.setGroup(player, AuthGroupType.UNREGISTERED);
|
||||
|
||||
@ -157,12 +152,8 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
final int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||
|
||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
||||
player.setOp(false);
|
||||
if (!service.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
|
||||
&& service.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
||||
player.setFlySpeed(0.0f);
|
||||
player.setWalkSpeed(0.0f);
|
||||
}
|
||||
limboService.createLimboPlayer(player, isAuthAvailable);
|
||||
|
||||
player.setNoDamageTicks(registrationTimeout);
|
||||
if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
|
||||
player.performCommand("motd");
|
||||
@ -174,40 +165,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
}
|
||||
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.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.permission.AdminPermission;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.permission.PlayerPermission;
|
||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||
import fr.xephi.authme.process.AsynchronousProcess;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
import fr.xephi.authme.process.SyncProcessManager;
|
||||
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.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
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.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
@ -46,15 +43,9 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
@Inject
|
||||
private CommonService service;
|
||||
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Inject
|
||||
private SyncProcessManager syncProcessManager;
|
||||
|
||||
@ -71,7 +62,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
private TempbanManager tempbanManager;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
private LimboService limboService;
|
||||
|
||||
AsynchronousLogin() {
|
||||
}
|
||||
@ -119,8 +110,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
if (auth == null) {
|
||||
service.send(player, MessageKey.UNKNOWN_USER);
|
||||
// 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)
|
||||
limboPlayerTaskManager.registerMessageTask(name, false);
|
||||
limboService.resetMessageTask(player, false);
|
||||
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 (captchaManager.isCaptchaRequired(player.getName())) {
|
||||
limboCache.getPlayerData(player.getName()).getMessageTask().setMuted(true);
|
||||
limboService.muteMessageTask(player);
|
||||
service.send(player, MessageKey.USAGE_CAPTCHA,
|
||||
captchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
|
||||
}
|
||||
@ -246,10 +236,6 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
// task, we schedule it in the end
|
||||
// so that we can be sure, and have not to care if it might be
|
||||
// processed in other order.
|
||||
LimboPlayer limboPlayer = limboCache.getPlayerData(name);
|
||||
if (limboPlayer != null) {
|
||||
limboPlayer.clearTasks();
|
||||
}
|
||||
syncProcessManager.processSyncPlayerLogin(player);
|
||||
} else {
|
||||
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);
|
||||
String command = service.getProperty(RestrictionSettings.OTHER_ACCOUNTS_CMD);
|
||||
|
||||
if(threshold < 2 || command.isEmpty()) {
|
||||
if (threshold < 2 || command.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -300,10 +286,10 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
|
||||
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
|
||||
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()));
|
||||
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,
|
||||
player.getName(), Integer.toString(auths.size()));
|
||||
onlinePlayer.sendMessage(message);
|
||||
@ -323,7 +309,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
|
||||
boolean hasReachedMaxLoggedInPlayersForIp(Player player, String ip) {
|
||||
// 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
|
||||
|| permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|
||||
|| service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|
||||
|| "127.0.0.1".equalsIgnoreCase(ip)
|
||||
|| "localhost".equalsIgnoreCase(ip)) {
|
||||
return false;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package fr.xephi.authme.process.login;
|
||||
|
||||
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.LimboService;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.events.LoginEvent;
|
||||
import fr.xephi.authme.events.RestoreInventoryEvent;
|
||||
@ -31,7 +31,7 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
||||
private BungeeService bungeeService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private LimboService limboService;
|
||||
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
@ -65,15 +65,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
|
||||
public void processPlayerLogin(Player player) {
|
||||
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
|
||||
if (limbo != null) {
|
||||
limboCache.restoreData(player);
|
||||
limboCache.deletePlayerData(player);
|
||||
// do we really need to use location from database for now?
|
||||
// because LimboCache#restoreData teleport player to last location.
|
||||
limboService.restoreData(player);
|
||||
}
|
||||
commonService.setGroup(player, AuthGroupType.LOGGED_IN);
|
||||
|
||||
if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||
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.PlayerCache;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.process.AsynchronousProcess;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
import fr.xephi.authme.process.SyncProcessManager;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -24,9 +23,6 @@ public class AsynchronousLogout implements AsynchronousProcess {
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Inject
|
||||
private SyncProcessManager syncProcessManager;
|
||||
|
||||
@ -47,7 +43,6 @@ public class AsynchronousLogout implements AsynchronousProcess {
|
||||
database.updateQuitLoc(auth);
|
||||
}
|
||||
|
||||
limboCache.addPlayerData(player);
|
||||
playerCache.removePlayer(name);
|
||||
database.setUnlogged(name);
|
||||
syncProcessManager.processSyncPlayerLogout(player);
|
||||
|
@ -2,17 +2,17 @@ package fr.xephi.authme.process.logout;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.SessionManager;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.events.LogoutEvent;
|
||||
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.permission.AuthGroupType;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
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.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.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
@ -34,7 +34,7 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
||||
private ProtocolLibService protocolLibService;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
private LimboService limboService;
|
||||
|
||||
@Inject
|
||||
private SessionManager sessionManager;
|
||||
@ -53,9 +53,6 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
||||
protocolLibService.sendBlankInventoryPacket(player);
|
||||
}
|
||||
|
||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
||||
|
||||
applyLogoutEffect(player);
|
||||
|
||||
// Player is now logout... Time to fire event !
|
||||
@ -71,21 +68,14 @@ public class ProcessSynchronousPlayerLogout implements SynchronousProcess {
|
||||
teleportationService.teleportOnJoin(player);
|
||||
|
||||
// Apply Blindness effect
|
||||
final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
||||
}
|
||||
|
||||
// Set player's data to unauthenticated
|
||||
limboService.createLimboPlayer(player, true);
|
||||
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;
|
||||
|
||||
import fr.xephi.authme.data.limbo.LimboPlayerStorage;
|
||||
import fr.xephi.authme.data.limbo.LimboCache;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.process.SynchronousProcess;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -11,22 +10,10 @@ import javax.inject.Inject;
|
||||
public class ProcessSyncronousPlayerQuit implements SynchronousProcess {
|
||||
|
||||
@Inject
|
||||
private LimboPlayerStorage limboPlayerStorage;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private LimboService limboService;
|
||||
|
||||
public void processSyncQuit(Player player) {
|
||||
if (limboCache.hasPlayerData(player.getName())) { // it mean player is not authenticated
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
limboService.restoreData(player);
|
||||
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.PlayerCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.initialization.factory.SingletonStore;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.process.AsynchronousProcess;
|
||||
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.settings.properties.RegistrationSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
@ -31,6 +34,8 @@ public class AsyncRegister implements AsynchronousProcess {
|
||||
private CommonService service;
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
@Inject
|
||||
private SingletonStore<RegistrationExecutor> registrationExecutorFactory;
|
||||
|
||||
AsyncRegister() {
|
||||
}
|
||||
@ -38,12 +43,16 @@ public class AsyncRegister implements AsynchronousProcess {
|
||||
/**
|
||||
* Performs the registration process for the given player.
|
||||
*
|
||||
* @param player the player to register
|
||||
* @param executor the registration executor to perform the registration with
|
||||
* @param variant the registration method
|
||||
* @param parameters the parameters
|
||||
* @param <P> parameters type
|
||||
*/
|
||||
public void register(Player player, RegistrationExecutor executor) {
|
||||
if (preRegisterCheck(player) && executor.isRegistrationAdmitted()) {
|
||||
executeRegistration(player, executor);
|
||||
public <P extends RegistrationParameters> void register(RegistrationMethod<P> variant, P parameters) {
|
||||
if (preRegisterCheck(parameters.getPlayer())) {
|
||||
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.
|
||||
*
|
||||
* @param player the player to register
|
||||
* @param parameters the registration parameters
|
||||
* @param executor the executor to perform the registration process with
|
||||
* @param <P> registration params type
|
||||
*/
|
||||
private void executeRegistration(Player player, RegistrationExecutor executor) {
|
||||
PlayerAuth auth = executor.buildPlayerAuth();
|
||||
private <P extends RegistrationParameters>
|
||||
void executeRegistration(P parameters, RegistrationExecutor<P> executor) {
|
||||
PlayerAuth auth = executor.buildPlayerAuth(parameters);
|
||||
if (database.saveAuth(auth)) {
|
||||
executor.executePostPersistAction();
|
||||
executor.executePostPersistAction(parameters);
|
||||
} else {
|
||||
service.send(player, MessageKey.ERROR);
|
||||
service.send(parameters.getPlayer(), MessageKey.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package fr.xephi.authme.process.register;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
import fr.xephi.authme.permission.AuthGroupType;
|
||||
import fr.xephi.authme.process.SynchronousProcess;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -18,7 +18,7 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
|
||||
private CommonService service;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
private LimboService limboService;
|
||||
|
||||
ProcessSyncEmailRegister() {
|
||||
}
|
||||
@ -27,9 +27,7 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
|
||||
service.setGroup(player, AuthGroupType.REGISTERED_UNAUTHENTICATED);
|
||||
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
|
||||
|
||||
final String name = player.getName().toLowerCase();
|
||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
||||
limboService.replaceTasksAfterRegistration(player);
|
||||
|
||||
player.saveData();
|
||||
ConsoleLogger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fr.xephi.authme.process.register;
|
||||
|
||||
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.permission.AuthGroupType;
|
||||
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.properties.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||
import fr.xephi.authme.task.LimboPlayerTaskManager;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -27,10 +26,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
|
||||
private CommonService service;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
private LimboService limboService;
|
||||
|
||||
@Inject
|
||||
private CommandManager commandManager;
|
||||
@ -44,10 +40,7 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
|
||||
* @param player the player
|
||||
*/
|
||||
private void requestLogin(Player player) {
|
||||
final String name = player.getName().toLowerCase();
|
||||
limboCache.updatePlayerData(player);
|
||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
||||
limboPlayerTaskManager.registerMessageTask(name, true);
|
||||
limboService.replaceTasksAfterRegistration(player);
|
||||
|
||||
if (player.isInsideVehicle() && player.getVehicle() != null) {
|
||||
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() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return PlayerAuth.builder()
|
||||
.name(player.getName().toLowerCase())
|
||||
|
@ -5,7 +5,7 @@ import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
/**
|
||||
* 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
|
||||
@ -14,20 +14,24 @@ public interface RegistrationExecutor {
|
||||
* If this method returns {@code false}, it is expected that the executor inform
|
||||
* 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
|
||||
*/
|
||||
boolean isRegistrationAdmitted();
|
||||
boolean isRegistrationAdmitted(P params);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
PlayerAuth buildPlayerAuth();
|
||||
PlayerAuth buildPlayerAuth(P params);
|
||||
|
||||
/**
|
||||
* 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.data.auth.PlayerAuth;
|
||||
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.message.MessageKey;
|
||||
import fr.xephi.authme.permission.AuthGroupHandler;
|
||||
import fr.xephi.authme.permission.AuthGroupType;
|
||||
import fr.xephi.authme.process.AsynchronousProcess;
|
||||
import fr.xephi.authme.service.CommonService;
|
||||
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.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.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
@ -43,10 +42,7 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
||||
private BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
private LimboService limboService;
|
||||
|
||||
@Inject
|
||||
private TeleportationService teleportationService;
|
||||
@ -111,12 +107,10 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
||||
teleportationService.teleportOnJoin(player);
|
||||
player.saveData();
|
||||
|
||||
limboCache.deletePlayerData(player);
|
||||
limboCache.addPlayerData(player);
|
||||
|
||||
limboPlayerTaskManager.registerTimeoutTask(player);
|
||||
limboPlayerTaskManager.registerMessageTask(name, false);
|
||||
applyBlindEffect(player);
|
||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
||||
limboService.createLimboPlayer(player, false);
|
||||
applyBlindEffect(player);
|
||||
});
|
||||
}
|
||||
authGroupHandler.setGroup(player, AuthGroupType.UNREGISTERED);
|
||||
service.send(player, MessageKey.UNREGISTERED_SUCCESS);
|
||||
@ -124,13 +118,8 @@ public class AsynchronousUnregister implements AsynchronousProcess {
|
||||
|
||||
private void applyBlindEffect(final Player player) {
|
||||
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||
final int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||
bukkitService.runTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
||||
}
|
||||
});
|
||||
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,36 +7,36 @@ import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
*/
|
||||
public enum HashAlgorithm {
|
||||
|
||||
BCRYPT(fr.xephi.authme.security.crypts.BCRYPT.class),
|
||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
||||
DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class),
|
||||
IPB3(fr.xephi.authme.security.crypts.IPB3.class),
|
||||
IPB4(fr.xephi.authme.security.crypts.IPB4.class),
|
||||
JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class),
|
||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
||||
BCRYPT(fr.xephi.authme.security.crypts.BCrypt.class),
|
||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCrypt2y.class),
|
||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CrazyCrypt1.class),
|
||||
DOUBLEMD5(fr.xephi.authme.security.crypts.DoubleMd5.class),
|
||||
IPB3(fr.xephi.authme.security.crypts.Ipb3.class),
|
||||
IPB4(fr.xephi.authme.security.crypts.Ipb4.class),
|
||||
JOOMLA(fr.xephi.authme.security.crypts.Joomla.class),
|
||||
MD5(fr.xephi.authme.security.crypts.Md5.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.Md5vB.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MyBB.class),
|
||||
PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
|
||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PhpBB.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PhpFusion.class),
|
||||
@Deprecated
|
||||
PLAINTEXT(fr.xephi.authme.security.crypts.PLAINTEXT.class),
|
||||
ROYALAUTH(fr.xephi.authme.security.crypts.ROYALAUTH.class),
|
||||
SALTED2MD5(fr.xephi.authme.security.crypts.SALTED2MD5.class),
|
||||
SALTEDSHA512(fr.xephi.authme.security.crypts.SALTEDSHA512.class),
|
||||
SHA1(fr.xephi.authme.security.crypts.SHA1.class),
|
||||
SHA256(fr.xephi.authme.security.crypts.SHA256.class),
|
||||
SHA512(fr.xephi.authme.security.crypts.SHA512.class),
|
||||
SMF(fr.xephi.authme.security.crypts.SMF.class),
|
||||
PLAINTEXT(fr.xephi.authme.security.crypts.PlainText.class),
|
||||
ROYALAUTH(fr.xephi.authme.security.crypts.RoyalAuth.class),
|
||||
SALTED2MD5(fr.xephi.authme.security.crypts.Salted2Md5.class),
|
||||
SALTEDSHA512(fr.xephi.authme.security.crypts.SaltedSha512.class),
|
||||
SHA1(fr.xephi.authme.security.crypts.Sha1.class),
|
||||
SHA256(fr.xephi.authme.security.crypts.Sha256.class),
|
||||
SHA512(fr.xephi.authme.security.crypts.Sha512.class),
|
||||
SMF(fr.xephi.authme.security.crypts.Smf.class),
|
||||
TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class),
|
||||
WBB3(fr.xephi.authme.security.crypts.WBB3.class),
|
||||
WBB4(fr.xephi.authme.security.crypts.WBB4.class),
|
||||
WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class),
|
||||
WORDPRESS(fr.xephi.authme.security.crypts.WORDPRESS.class),
|
||||
XAUTH(fr.xephi.authme.security.crypts.XAUTH.class),
|
||||
XFBCRYPT(fr.xephi.authme.security.crypts.XFBCRYPT.class),
|
||||
WBB3(fr.xephi.authme.security.crypts.Wbb3.class),
|
||||
WBB4(fr.xephi.authme.security.crypts.Wbb4.class),
|
||||
WHIRLPOOL(fr.xephi.authme.security.crypts.Whirlpool.class),
|
||||
WORDPRESS(fr.xephi.authme.security.crypts.Wordpress.class),
|
||||
XAUTH(fr.xephi.authme.security.crypts.XAuth.class),
|
||||
XFBCRYPT(fr.xephi.authme.security.crypts.XfBCrypt.class),
|
||||
CUSTOM(null);
|
||||
|
||||
private final Class<? extends EncryptionMethod> clazz;
|
||||
|
@ -14,12 +14,12 @@ import javax.inject.Inject;
|
||||
|
||||
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
||||
@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting
|
||||
public class BCRYPT implements EncryptionMethod {
|
||||
public class BCrypt implements EncryptionMethod {
|
||||
|
||||
private final int bCryptLog2Rounds;
|
||||
|
||||
@Inject
|
||||
public BCRYPT(Settings settings) {
|
||||
public BCrypt(Settings settings) {
|
||||
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;
|
||||
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class BCRYPT2Y extends HexSaltedMethod {
|
||||
public class BCrypt2y extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
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.security.MessageDigest;
|
||||
|
||||
public class CRAZYCRYPT1 extends UsernameSaltMethod {
|
||||
public class CrazyCrypt1 extends UsernameSaltMethod {
|
||||
|
||||
private static final char[] CRYPTCHARS =
|
||||
{'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;
|
||||
|
||||
public class DOUBLEMD5 extends UnsaltedMethod {
|
||||
public class DoubleMd5 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password) {
|
@ -10,7 +10,7 @@ import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
@Recommendation(Usage.ACCEPTABLE)
|
||||
@HasSalt(value = SaltType.TEXT, length = 5)
|
||||
public class IPB3 extends SeparateSaltMethod {
|
||||
public class Ipb3 extends SeparateSaltMethod {
|
||||
|
||||
@Override
|
||||
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>
|
||||
* 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).
|
||||
*/
|
||||
@Recommendation(Usage.DOES_NOT_WORK)
|
||||
@HasSalt(value = SaltType.TEXT, length = 22)
|
||||
public class IPB4 implements EncryptionMethod {
|
||||
public class Ipb4 implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
@Recommendation(Usage.ACCEPTABLE)
|
||||
public class JOOMLA extends HexSaltedMethod {
|
||||
public class Joomla extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
public class MD5 extends UnsaltedMethod {
|
||||
public class Md5 extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password) {
|
@ -2,7 +2,7 @@ package fr.xephi.authme.security.crypts;
|
||||
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
public class MD5VB extends HexSaltedMethod {
|
||||
public class Md5vB extends HexSaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
@ -10,7 +10,7 @@ import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
@Recommendation(Usage.ACCEPTABLE)
|
||||
@HasSalt(value = SaltType.TEXT, length = 8)
|
||||
public class MYBB extends SeparateSaltMethod {
|
||||
public class MyBB extends SeparateSaltMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
@ -9,7 +9,7 @@ import java.security.MessageDigest;
|
||||
/**
|
||||
* @author stefano
|
||||
*/
|
||||
public class PHPBB extends HexSaltedMethod {
|
||||
public class PhpBB extends HexSaltedMethod {
|
||||
|
||||
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user