commit
afd4498184
25
.github/ISSUE_TEMPLATE.MD
vendored
Normal file
25
.github/ISSUE_TEMPLATE.MD
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
####Before reporting an issue make sure you are running the latest build of the plugin!
|
||||||
|
|
||||||
|
### What behaviour is observed:
|
||||||
|
What happened?
|
||||||
|
|
||||||
|
### What behaviour is expected:
|
||||||
|
What did you expect?
|
||||||
|
|
||||||
|
### Steps/models to reproduce:
|
||||||
|
The actions that cause the issue
|
||||||
|
|
||||||
|
### Plugin list:
|
||||||
|
This can be found by running `/pl`
|
||||||
|
|
||||||
|
### Environment description
|
||||||
|
Standalone server/Bungeecord network, SQLite/MYSql, ...
|
||||||
|
|
||||||
|
### AuthMe build number:
|
||||||
|
This can be found by running `/authme version`
|
||||||
|
|
||||||
|
### Error Log:
|
||||||
|
Pastebin/Hastebin/Gist link of the error logo or stacktrace (if any)
|
||||||
|
|
||||||
|
### Configuration:
|
||||||
|
Pastebin/Hastebin/Gist link of your config.yml file (remember to delete any sensible data)
|
||||||
273
.idea/codeStyleSettings.xml
generated
273
.idea/codeStyleSettings.xml
generated
@ -12,9 +12,280 @@
|
|||||||
<XML>
|
<XML>
|
||||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||||
</XML>
|
</XML>
|
||||||
|
<codeStyleSettings language="JAVA">
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PUBLIC>true</PUBLIC>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PROTECTED>true</PROTECTED>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PRIVATE>true</PRIVATE>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PUBLIC>true</PUBLIC>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PROTECTED>true</PROTECTED>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PRIVATE>true</PRIVATE>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PUBLIC>true</PUBLIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PROTECTED>true</PROTECTED>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<FINAL>true</FINAL>
|
||||||
|
<PRIVATE>true</PRIVATE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PUBLIC>true</PUBLIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PROTECTED>true</PROTECTED>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
<PRIVATE>true</PRIVATE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<FIELD>true</FIELD>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<CONSTRUCTOR>true</CONSTRUCTOR>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<METHOD>true</METHOD>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<METHOD>true</METHOD>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<METHOD>true</METHOD>
|
||||||
|
<PRIVATE>true</PRIVATE>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<ENUM>true</ENUM>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<INTERFACE>true</INTERFACE>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<CLASS>true</CLASS>
|
||||||
|
<STATIC>true</STATIC>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<CLASS>true</CLASS>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Project" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
69
README.md
69
README.md
@ -2,23 +2,23 @@
|
|||||||
<p align="center"><strong>The most used authentication plugin for CraftBukkit/Spigot!</strong></p>
|
<p align="center"><strong>The most used authentication plugin for CraftBukkit/Spigot!</strong></p>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
#####News:
|
|
||||||
|
|
||||||
- Latest version of AuthMeBridge is finally compatible with latest AuthMe snapshots! ;)
|
|
||||||
|
|
||||||
#####Development tools:
|
#####Development tools:
|
||||||
|
|
||||||
- DEVELOPMENT TEAM REPO (<strong>please send PRs here!</strong>): <a href="https://github.com/AuthMe-Team/AuthMeReloaded">Github Development Page</a>
|
- MAIN REPO (**release sources, issue tracker!**): [Github Main Page](https://github.com/Xephi/AuthMeReloaded)
|
||||||
|
|
||||||
|
- DEVELOPMENT TEAM REPO (**latest sources, please send PRs here!**): [Github Development Page](https://github.com/AuthMe/AuthMeReloaded)
|
||||||
|
|
||||||
- Developers ChatRoom: [](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
- Developers ChatRoom: [](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
- Build Server (<strong>DEVELOPMENT BUILDS</strong>): <a href="http://ci.xephi.fr/job/AuthMeReloaded">Xephi's Jenkins</a>
|
- Build Server (**DEVELOPMENT BUILDS**): [Xephi's Jenkins](http://ci.xephi.fr/job/AuthMeReloaded)
|
||||||
|
|
||||||
- Build status: [](https://travis-ci.org/AuthMe-Team/AuthMeReloaded) [](https://www.versioneye.com/user/projects/55bab9e8653762002000190a)
|
- Build status: [](https://travis-ci.org/AuthMe/AuthMeReloaded)
|
||||||
|
|
||||||
- Build status (CircleCI): [](https://circleci.com/gh/AuthMe-Team/AuthMeReloaded)
|
- Dependencies: [](https://www.versioneye.com/user/projects/5617ca36a193340f28000222)
|
||||||
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe-Team/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
|
|
||||||
- JitPack (just in case): [](https://jitpack.io/#AuthMe-Team/AuthMeReloaded)
|
- Build status (CircleCI): [](https://circleci.com/gh/AuthMe/AuthMeReloaded)
|
||||||
|
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
|
||||||
|
- JitPack (just in case): [](https://jitpack.io/#AuthMe/AuthMeReloaded)
|
||||||
|
|
||||||
- Code Coverage: [](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
- Code Coverage: [](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
||||||
|
|
||||||
@ -39,6 +39,7 @@ McStats: http://mcstats.org/plugin/AuthMe
|
|||||||
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
|
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
|
||||||
|
|
||||||
#####Development history:
|
#####Development history:
|
||||||
|
Outdated!
|
||||||
[](https://www.youtube.com/watch?v=hJRzNfYyd9k)
|
[](https://www.youtube.com/watch?v=hJRzNfYyd9k)
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@ -53,8 +54,8 @@ McStats: http://mcstats.org/plugin/AuthMe
|
|||||||
>- Execute command "mvn clean install"
|
>- Execute command "mvn clean install"
|
||||||
|
|
||||||
#####Running Requirements:
|
#####Running Requirements:
|
||||||
>- Java 1.7 (should work also with Java 1.8)
|
>- Java 1.7 or 1.8
|
||||||
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X or 1.9.X)
|
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X)
|
||||||
>- ProtocolLib (optional, required by the protectInventory feature)
|
>- ProtocolLib (optional, required by the protectInventory feature)
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@ -62,13 +63,16 @@ McStats: http://mcstats.org/plugin/AuthMe
|
|||||||
|
|
||||||
#####"The best authentication plugin for the Bukkit/Spigot API!"
|
#####"The best authentication plugin for the Bukkit/Spigot API!"
|
||||||
|
|
||||||
<p>Prevent username stealing on your server!<br>
|
Prevent username stealing on your server!<br>
|
||||||
Use it to secure your Offline mode server or to increase your Online mode server's protection!</p>
|
Use it to secure your Offline mode server or to increase your Online mode server's protection!
|
||||||
|
|
||||||
<p>AuthMeReloaded disallows players who aren't authenticated to do actions like placing blocks, moving,<br>
|
AuthMeReloaded disallows players who aren't authenticated to do actions like placing blocks, moving,<br>
|
||||||
typing commands or using the inventory. It can also kick players with uncommonly long or short player names or kick players from banned countries.</p>
|
typing commands or using the inventory. It can also kick players with uncommonly long or short player names or kick players from banned countries.
|
||||||
<p>With the Session Login feature you don't have to execute the authentication command every time you connect to the server! Each command and every feature can be enabled or disabled from our well structured configuration file.</p>
|
|
||||||
<p>You can also create your own translation file and, if you want, you can share it with us! :)</p>
|
With the Session Login feature you don't have to execute the authentication command every time you connect to the server!
|
||||||
|
Each command and every feature can be enabled or disabled from our well structured configuration file.
|
||||||
|
|
||||||
|
You can also create your own translation file and, if you want, you can share it with us! :)
|
||||||
|
|
||||||
####Features:
|
####Features:
|
||||||
<ul>
|
<ul>
|
||||||
@ -114,24 +118,25 @@ typing commands or using the inventory. It can also kick players with uncommonly
|
|||||||
####Email Recovery Dependency
|
####Email Recovery Dependency
|
||||||
<a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-configure-email-recovery-system/">How to configure email recovery system?</a>
|
<a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-configure-email-recovery-system/">How to configure email recovery system?</a>
|
||||||
####Commands
|
####Commands
|
||||||
<a href="https://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/commands.md">Command list and usage</a>
|
[Command list and usage](https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/commands.md)
|
||||||
####Permissions
|
####Permissions
|
||||||
<ul><li>authme.player.* - for all user commands
|
- authme.player.* - for all user commands
|
||||||
</li><li>authme.admin.* - for all admin commands
|
- authme.admin.* - for all admin commands
|
||||||
</li><li><a href="https://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md">List of all single permissions</a>
|
- [List of all permission nodes](http://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md)
|
||||||
</li></ul>
|
|
||||||
####How To
|
####How To
|
||||||
<ul><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-install-and-initial-configuration/">How to Install and Setup</a>
|
- [How to install and set up](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-install-and-initial-configuration/)
|
||||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-xauth/">How to import database from xAuth</a>
|
- [How to import database from xAuth](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-xauth/)
|
||||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/">Website Integration</a>
|
- [Website integration](http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/)
|
||||||
</li><li><a href="https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml">Click here for an example of the Config file</a>
|
- [Click here for an example of the config file](https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml)
|
||||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/">How to convert from Rakamak</a>
|
- [How to convert from Rakamak](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/)
|
||||||
</li><li>Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
|
- Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
|
||||||
</li></ul>
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
#####GeoIP
|
#####GeoIP
|
||||||
<p>This product uses data from the GeoLite API created by MaxMind, available at <a href="http://www.maxmind.com">http://www.maxmind.com</a></p>
|
This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
#####Donate
|
#####Donate
|
||||||
@ -144,6 +149,6 @@ GameHosting.it is leader in Italy as Game Server Provider. With its own DataCent
|
|||||||
[](http://www.gamehosting.it)
|
[](http://www.gamehosting.it)
|
||||||
|
|
||||||
#####Credits
|
#####Credits
|
||||||
<p>Team members: look at the <a href="https://github.com/AuthMe-Team/AuthMeReloaded/blob/master/team.txt">team.txt file</a>
|
<p>Team members: look at the <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/team.txt">team.txt file</a>
|
||||||
<p>Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka</p>
|
<p>Credit for old version of the plugin to: d4rkwarriors, fabe1337, Whoami2 and pomo4ka</p>
|
||||||
<p>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p>
|
<p>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Thu Apr 07 17:17:20 CEST 2016. See commands/commands.tpl.md -->
|
<!-- File auto-generated on Wed Jun 22 17:39:14 EDT 2016. See commands/commands.tpl.md -->
|
||||||
|
|
||||||
## AuthMe Commands
|
## AuthMe Commands
|
||||||
You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >`
|
You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >`
|
||||||
@ -55,9 +55,9 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
|
|||||||
- **/register** [password] [verifyPassword]: Command to register using AuthMeReloaded.
|
- **/register** [password] [verifyPassword]: Command to register using AuthMeReloaded.
|
||||||
<br />Requires `authme.player.register`
|
<br />Requires `authme.player.register`
|
||||||
- **/register help** [query]: View detailed help for /register commands.
|
- **/register help** [query]: View detailed help for /register commands.
|
||||||
- **/unreg** <password>: Command to unregister using AuthMeReloaded.
|
- **/unregister** <password>: Command to unregister using AuthMeReloaded.
|
||||||
<br />Requires `authme.player.unregister`
|
<br />Requires `authme.player.unregister`
|
||||||
- **/unreg help** [query]: View detailed help for /unreg commands.
|
- **/unregister help** [query]: View detailed help for /unregister commands.
|
||||||
- **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded.
|
- **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded.
|
||||||
<br />Requires `authme.player.changepassword`
|
<br />Requires `authme.player.changepassword`
|
||||||
- **/changepassword help** [query]: View detailed help for /changepassword commands.
|
- **/changepassword help** [query]: View detailed help for /changepassword commands.
|
||||||
@ -73,6 +73,7 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
|
|||||||
<br />Requires `authme.player.captcha`
|
<br />Requires `authme.player.captcha`
|
||||||
- **/captcha help** [query]: View detailed help for /captcha commands.
|
- **/captcha help** [query]: View detailed help for /captcha commands.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:20 CEST 2016
|
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:14 EDT 2016
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Thu Apr 07 17:17:22 CEST 2016. See hashmethods/hash_algorithms.tpl.md -->
|
<!-- File auto-generated on Wed Jun 22 17:39:16 EDT 2016. See hashmethods/hash_algorithms.tpl.md -->
|
||||||
|
|
||||||
## Hash Algorithms
|
## Hash Algorithms
|
||||||
AuthMe supports the following hash algorithms for storing your passwords safely.
|
AuthMe supports the following hash algorithms for storing your passwords safely.
|
||||||
@ -82,4 +82,4 @@ or bad.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:22 CEST 2016
|
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:16 EDT 2016
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
|
||||||
<!-- File auto-generated on Thu Apr 07 17:17:24 CEST 2016. See permissions/permission_nodes.tpl.md -->
|
<!-- File auto-generated on Wed Jun 22 17:39:29 EDT 2016. See permissions/permission_nodes.tpl.md -->
|
||||||
|
|
||||||
## AuthMe Permission Nodes
|
## AuthMe Permission Nodes
|
||||||
The following are the permission nodes that are currently supported by the latest dev builds.
|
The following are the permission nodes that are currently supported by the latest dev builds.
|
||||||
@ -28,6 +28,7 @@ The following are the permission nodes that are currently supported by the lates
|
|||||||
- **authme.allowmultipleaccounts** – Permission to be able to register multiple accounts.
|
- **authme.allowmultipleaccounts** – Permission to be able to register multiple accounts.
|
||||||
- **authme.bypassantibot** – Permission node to bypass AntiBot protection.
|
- **authme.bypassantibot** – Permission node to bypass AntiBot protection.
|
||||||
- **authme.bypassforcesurvival** – Permission for users to bypass force-survival mode.
|
- **authme.bypassforcesurvival** – Permission for users to bypass force-survival mode.
|
||||||
|
- **authme.bypasspurge** – Permission to bypass the purging process
|
||||||
- **authme.player.*** – Permission to use all player (non-admin) commands.
|
- **authme.player.*** – Permission to use all player (non-admin) commands.
|
||||||
- **authme.player.canbeforced** – Permission for users a login can be forced to.
|
- **authme.player.canbeforced** – Permission for users a login can be forced to.
|
||||||
- **authme.player.captcha** – Command permission to use captcha.
|
- **authme.player.captcha** – Command permission to use captcha.
|
||||||
@ -42,6 +43,7 @@ The following are the permission nodes that are currently supported by the lates
|
|||||||
- **authme.player.unregister** – Command permission to unregister.
|
- **authme.player.unregister** – Command permission to unregister.
|
||||||
- **authme.vip** – Permission node to identify VIP users.
|
- **authme.vip** – Permission node to identify VIP users.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Thu Apr 07 17:17:24 CEST 2016
|
This page was automatically generated on the [AuthMe-Team/AuthMeReloaded repository](https://github.com/AuthMe-Team/AuthMeReloaded/tree/master/docs/) on Wed Jun 22 17:39:29 EDT 2016
|
||||||
|
|||||||
260
pom.xml
260
pom.xml
@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
<groupId>fr.xephi</groupId>
|
<groupId>fr.xephi</groupId>
|
||||||
<artifactId>authme</artifactId>
|
<artifactId>authme</artifactId>
|
||||||
<version>5.2-BETA3</version>
|
<version>5.2-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<name>AuthMeReloaded</name>
|
<name>AuthMeReloaded</name>
|
||||||
<description>The first authentication plugin for the Bukkit API!</description>
|
<description>The first authentication plugin for the Bukkit API!</description>
|
||||||
@ -17,13 +16,13 @@
|
|||||||
|
|
||||||
<organization>
|
<organization>
|
||||||
<name>AuthMe-Team</name>
|
<name>AuthMe-Team</name>
|
||||||
<url>https://github.com/AuthMe-Team</url>
|
<url>https://github.com/AuthMe</url>
|
||||||
</organization>
|
</organization>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:https://github.com/AuthMe-Team/AuthMeReloaded.git</connection>
|
<connection>scm:git:https://github.com/AuthMe/AuthMeReloaded.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:AuthMe-Team/AuthMeReloaded.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:AuthMe/AuthMeReloaded.git</developerConnection>
|
||||||
<url>https://github.com/AuthMe-Team/AuthMeReloaded</url>
|
<url>https://github.com/AuthMe/AuthMeReloaded</url>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<ciManagement>
|
<ciManagement>
|
||||||
@ -44,10 +43,6 @@
|
|||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
<prerequisites>
|
|
||||||
<maven>3.3.3</maven>
|
|
||||||
</prerequisites>
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Project properties -->
|
<!-- Project properties -->
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
@ -62,15 +57,17 @@
|
|||||||
|
|
||||||
<!-- BukkitPlugin properties -->
|
<!-- BukkitPlugin properties -->
|
||||||
<bukkitplugin.name>${project.outputName}</bukkitplugin.name>
|
<bukkitplugin.name>${project.outputName}</bukkitplugin.name>
|
||||||
|
<bukkitplugin.version>${project.versionCode}</bukkitplugin.version>
|
||||||
<bukkitplugin.main>${project.groupId}.${project.artifactId}.${bukkitplugin.name}</bukkitplugin.main>
|
<bukkitplugin.main>${project.groupId}.${project.artifactId}.${bukkitplugin.name}</bukkitplugin.main>
|
||||||
<bukkitplugin.authors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu</bukkitplugin.authors>
|
<bukkitplugin.authors>Xephi, sgdc3, DNx5, timvisee, games647, ljacqu, Gnat008</bukkitplugin.authors>
|
||||||
|
|
||||||
<!-- Change Bukkit Version HERE! -->
|
<!-- Change Bukkit Version HERE! -->
|
||||||
<bukkit.version>1.10-R0.1-SNAPSHOT</bukkit.version>
|
<bukkit.version>1.10-R0.1-SNAPSHOT</bukkit.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<!-- Jenkins profile (add the real buildNumber to the version string) -->
|
<!-- Jenkins profile -->
|
||||||
<profiles>
|
<profiles>
|
||||||
|
<!-- Set the buildNumber using the jenkins env. variable -->
|
||||||
<profile>
|
<profile>
|
||||||
<id>jenkins</id>
|
<id>jenkins</id>
|
||||||
<activation>
|
<activation>
|
||||||
@ -82,6 +79,7 @@
|
|||||||
<project.buildNumber>${env.BUILD_NUMBER}</project.buildNumber>
|
<project.buildNumber>${env.BUILD_NUMBER}</project.buildNumber>
|
||||||
</properties>
|
</properties>
|
||||||
</profile>
|
</profile>
|
||||||
|
<!-- Skip long hash tests, reduce the test time of 20-30 seconds -->
|
||||||
<profile>
|
<profile>
|
||||||
<id>skipLongHashTests</id>
|
<id>skipLongHashTests</id>
|
||||||
<activation>
|
<activation>
|
||||||
@ -93,10 +91,85 @@
|
|||||||
<project.skipExtendedHashTests>true</project.skipExtendedHashTests>
|
<project.skipExtendedHashTests>true</project.skipExtendedHashTests>
|
||||||
</properties>
|
</properties>
|
||||||
</profile>
|
</profile>
|
||||||
|
<!-- Spigot, default -->
|
||||||
|
<profile>
|
||||||
|
<id>spigot</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>${bukkit.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>persistence-api</artifactId>
|
||||||
|
<groupId>javax.persistence</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>bungeecord-chat</artifactId>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
<!-- Bukkit -->
|
||||||
|
<profile>
|
||||||
|
<id>bukkit</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bukkit</groupId>
|
||||||
|
<artifactId>bukkit</artifactId>
|
||||||
|
<version>${bukkit.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>persistence-api</artifactId>
|
||||||
|
<groupId>javax.persistence</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<!-- Name of the NOSHADE jar (no shaded/relocated libraries) -->
|
<!-- Name of the unshaded jar (no shaded/relocated libraries) -->
|
||||||
<finalName>${project.finalName}-noshade</finalName>
|
<finalName>${project.finalName}-noshade</finalName>
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
@ -135,6 +208,7 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.19.1</version>
|
<version>2.19.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<!-- Force the right file encoding during unit testing -->
|
||||||
<argLine>-Dfile.encoding=${project.build.sourceEncoding} @{argLine}</argLine>
|
<argLine>-Dfile.encoding=${project.build.sourceEncoding} @{argLine}</argLine>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<project.skipExtendedHashTests>${project.skipExtendedHashTests}</project.skipExtendedHashTests>
|
<project.skipExtendedHashTests>${project.skipExtendedHashTests}</project.skipExtendedHashTests>
|
||||||
@ -143,20 +217,16 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
<!-- Libs Shading and Relocation -->
|
<!-- Libs Shading and Relocation -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<!--
|
|
||||||
Relocate all lib we use in order to fix class loading errors if we use different versions
|
|
||||||
than already loaded libs (i.e. by Mojang -> gson)
|
|
||||||
-->
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4.3</version>
|
<version>2.4.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
<!--
|
|
||||||
Let's try to remove this!
|
|
||||||
<minimizeJar>false</minimizeJar>
|
|
||||||
-->
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<!--
|
||||||
|
Relocate all lib we use in order to fix class loading errors if we use different versions
|
||||||
|
than already loaded libs (i.e. by Mojang -> gson)
|
||||||
|
-->
|
||||||
<executions>
|
<executions>
|
||||||
<!-- Spigot 1.8+ -->
|
<!-- Spigot 1.8+ -->
|
||||||
<execution>
|
<execution>
|
||||||
@ -170,39 +240,35 @@
|
|||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.guava:guava</exclude>
|
<exclude>com.google.guava:guava</exclude>
|
||||||
|
<exclude>com.google.code.gson:gson</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
<relocations>
|
<relocations>
|
||||||
<!-- We use a newer version of gson so we need to include it! -->
|
<relocation>
|
||||||
<relocation>
|
<pattern>com.zaxxer.hikari</pattern>
|
||||||
<pattern>com.google.gson</pattern>
|
<shadedPattern>fr.xephi.authme.libs.zaxxer.hikari</shadedPattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.google</shadedPattern>
|
</relocation>
|
||||||
</relocation>
|
<relocation>
|
||||||
<relocation>
|
<pattern>org.slf4j</pattern>
|
||||||
<pattern>com.zaxxer.hikari</pattern>
|
<shadedPattern>fr.xephi.authme.libs.slf4j.slf4j</shadedPattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.hikari</shadedPattern>
|
</relocation>
|
||||||
</relocation>
|
<relocation>
|
||||||
<relocation>
|
<pattern>com.maxmind.geoip</pattern>
|
||||||
<pattern>org.slf4j</pattern>
|
<shadedPattern>fr.xephi.authme.libs.maxmind.geoip</shadedPattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.slf4j</shadedPattern>
|
</relocation>
|
||||||
</relocation>
|
<relocation>
|
||||||
<relocation>
|
<pattern>net.ricecode.similarity</pattern>
|
||||||
<pattern>com.maxmind.geoip</pattern>
|
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.geoip</shadedPattern>
|
</relocation>
|
||||||
</relocation>
|
<relocation>
|
||||||
<relocation>
|
<pattern>javax.inject</pattern>
|
||||||
<pattern>net.ricecode.similarity</pattern>
|
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
|
</relocation>
|
||||||
</relocation>
|
<!-- MCStats.org metrics -->
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>javax.inject</pattern>
|
<pattern>org.mcstats</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
|
<shadedPattern>fr.xephi.authme</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<!-- MCStats.org metrics -->
|
|
||||||
<relocation>
|
|
||||||
<pattern>org.mcstats</pattern>
|
|
||||||
<shadedPattern>fr.xephi.authme</shadedPattern>
|
|
||||||
</relocation>
|
|
||||||
</relocations>
|
</relocations>
|
||||||
<outputFile>target/${project.finalName}-spigot.jar</outputFile>
|
<outputFile>target/${project.finalName}-spigot.jar</outputFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
@ -215,31 +281,31 @@
|
|||||||
<goal>shade</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- Include all google libraries, because they are not available before 1.8 -->
|
|
||||||
<relocations>
|
<relocations>
|
||||||
|
<!-- Include all google libraries, because they are not available before 1.8 -->
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.google</pattern>
|
<pattern>com.google</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.google</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.google</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.zaxxer.hikari</pattern>
|
<pattern>com.zaxxer.hikari</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.hikari</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.zaxxer.hikari</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>org.slf4j</pattern>
|
<pattern>org.slf4j</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.slf4j</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.slf4j.slf4j</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.maxmind.geoip</pattern>
|
<pattern>com.maxmind.geoip</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.geoip</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.maxmind.geoip</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>net.ricecode.similarity</pattern>
|
<pattern>net.ricecode.similarity</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>javax.inject</pattern>
|
<pattern>javax.inject</pattern>
|
||||||
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
|
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
<!-- MCStats.org metrics -->
|
<!-- MCStats.org metrics -->
|
||||||
<relocation>
|
<relocation>
|
||||||
@ -252,7 +318,7 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Exec Tools -->
|
<!-- Exec Plugin (Tools runner) -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
@ -267,7 +333,7 @@
|
|||||||
<includeProjectDependencies>true</includeProjectDependencies>
|
<includeProjectDependencies>true</includeProjectDependencies>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Test coverage -->
|
<!-- Coverage report generator -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
@ -281,7 +347,7 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Coveralls data -->
|
<!-- Coverage report uploader -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eluder.coveralls</groupId>
|
<groupId>org.eluder.coveralls</groupId>
|
||||||
<artifactId>coveralls-maven-plugin</artifactId>
|
<artifactId>coveralls-maven-plugin</artifactId>
|
||||||
@ -289,9 +355,9 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<failOnServiceError>false</failOnServiceError>
|
<failOnServiceError>false</failOnServiceError>
|
||||||
</configuration>
|
</configuration>
|
||||||
<!-- The secret token is provided by console! -->
|
<!-- The secret token is provided with a command-line parameter! -->
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Javadocs settings -->
|
<!-- JavaDocs generator -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
@ -305,9 +371,9 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<!-- SpigotMC Repo (Bukkit and SpigotAPI) -->
|
<!-- SpigotAPI Repo -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-repo</id>
|
<id>spigotmc-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
@ -319,7 +385,7 @@
|
|||||||
|
|
||||||
<!-- CombatTagPlus Repo -->
|
<!-- CombatTagPlus Repo -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>minelink-thirdparty</id>
|
<id>minelink-repo</id>
|
||||||
<url>http://repo.minelink.net/content/repositories/public</url>
|
<url>http://repo.minelink.net/content/repositories/public</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
@ -331,33 +397,27 @@
|
|||||||
|
|
||||||
<!-- Multiverse Repo -->
|
<!-- Multiverse Repo -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>onarandombox</id>
|
<id>onarandombox-repo</id>
|
||||||
<url>http://repo.onarandombox.com/content/groups/public</url>
|
<url>http://repo.onarandombox.com/content/groups/public</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<!-- Vault Repo -->
|
<!-- Vault Repo -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>vault-repo</id>
|
<id>vault-repo</id>
|
||||||
<url>http://nexus.theyeticave.net/content/repositories/pub_releases</url>
|
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<!-- XAuth Repo -->
|
<!-- XAuth Repo -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>luricos-releases</id>
|
<id>luricos-repo</id>
|
||||||
<url>http://repo.luricos.de/content/repositories/releases</url>
|
<url>http://repo.luricos.de/content/repositories/releases</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<!-- Xephi Repo -->
|
<!-- Our Repo (Many libs) -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>xephi-repo</id>
|
<id>xephi-repo</id>
|
||||||
<url>http://ci.xephi.fr/plugin/repository/everything/</url>
|
<url>http://ci.xephi.fr/plugin/repository/everything/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<!-- PermissionsEx Repo (Re-added, since Xephi's repo was down) -->
|
|
||||||
<repository>
|
|
||||||
<id>pex-repo</id>
|
|
||||||
<url>https://pex-repo.aoeu.xyz/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -365,7 +425,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
<version>2.4.6</version>
|
<version>2.4.7</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
@ -375,6 +435,7 @@
|
|||||||
</exclusions>
|
</exclusions>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- HikariCP Logger -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
@ -387,8 +448,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
<!-- Can't use newer versions due to api changes! -->
|
<version>2.5</version>
|
||||||
<version>2.0-beta9</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@ -401,11 +461,11 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- GSON (required to provide 1.7.10 and below compatibility) -->
|
<!-- GSON (version included in spigot 1.8+, required to provide 1.7.10 and below compatibility) -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.6.2</version>
|
<version>2.2.4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -453,38 +513,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
<!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||||
<dependency>
|
<!-- Moved in profiles! -->
|
||||||
<groupId>org.spigotmc</groupId>
|
|
||||||
<artifactId>spigot-api</artifactId>
|
|
||||||
<version>${bukkit.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>json-simple</artifactId>
|
|
||||||
<groupId>com.googlecode.json-simple</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>persistence-api</artifactId>
|
|
||||||
<groupId>javax.persistence</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>bungeecord-chat</artifactId>
|
|
||||||
<groupId>net.md-5</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- ProtocolLib, http://dev.bukkit.org/bukkit-plugins/protocollib/ -->
|
<!-- ProtocolLib, http://dev.bukkit.org/bukkit-plugins/protocollib/ -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -807,6 +836,13 @@
|
|||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Injector -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.jalu</groupId>
|
||||||
|
<artifactId>injector</artifactId>
|
||||||
|
<version>0.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- String comparison library. Used for dynamic help system. -->
|
<!-- String comparison library. Used for dynamic help system. -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.ricecode</groupId>
|
<groupId>net.ricecode</groupId>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
* verification). Don't forget to update the AUTHME_TABLE value and your *
|
* verification). Don't forget to update the AUTHME_TABLE value and your *
|
||||||
* database credentials in getAuthmeMySqli(). *
|
* database credentials in getAuthmeMySqli(). *
|
||||||
* *
|
* *
|
||||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
abstract class AuthMeController {
|
abstract class AuthMeController {
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* ------------------------------------------------------- *
|
* ------------------------------------------------------- *
|
||||||
* See AuthMeController for details. *
|
* See AuthMeController for details. *
|
||||||
* *
|
* *
|
||||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||||
***********************************************************/
|
***********************************************************/
|
||||||
class Bcrypt extends AuthMeController {
|
class Bcrypt extends AuthMeController {
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* ------------------------------------------------------- *
|
* ------------------------------------------------------- *
|
||||||
* See AuthMeController for details. *
|
* See AuthMeController for details. *
|
||||||
* *
|
* *
|
||||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||||
***********************************************************/
|
***********************************************************/
|
||||||
class Sha256 extends AuthMeController {
|
class Sha256 extends AuthMeController {
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import fr.xephi.authme.output.MessageKey;
|
|||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -20,16 +20,16 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
|
|||||||
*/
|
*/
|
||||||
public class AntiBot {
|
public class AntiBot {
|
||||||
|
|
||||||
private final NewSetting settings;
|
private final Settings settings;
|
||||||
private final Messages messages;
|
private final Messages messages;
|
||||||
private final PermissionsManager permissionsManager;
|
private final PermissionsManager permissionsManager;
|
||||||
private final BukkitService bukkitService;
|
private final BukkitService bukkitService;
|
||||||
public final CopyOnWriteArrayList<String> antibotKicked = new CopyOnWriteArrayList<String>();
|
private final CopyOnWriteArrayList<String> antibotKicked = new CopyOnWriteArrayList<String>();
|
||||||
private final CopyOnWriteArrayList<String> antibotPlayers = new CopyOnWriteArrayList<String>();
|
private final CopyOnWriteArrayList<String> antibotPlayers = new CopyOnWriteArrayList<String>();
|
||||||
private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED;
|
private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager,
|
AntiBot(Settings settings, Messages messages, PermissionsManager permissionsManager,
|
||||||
BukkitService bukkitService) {
|
BukkitService bukkitService) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
@ -112,6 +112,27 @@ public class AntiBot {
|
|||||||
}, 15 * TICKS_PER_SECOND);
|
}, 15 * TICKS_PER_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the player was kicked because of activated antibot. The list is reset
|
||||||
|
* when antibot is deactivated.
|
||||||
|
*
|
||||||
|
* @param name the name to check
|
||||||
|
* @return true if the given name has been kicked because of Antibot
|
||||||
|
*/
|
||||||
|
public boolean wasPlayerKicked(String name) {
|
||||||
|
return antibotKicked.contains(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a name to the list of players kicked by antibot. Should only be used when a player
|
||||||
|
* is determined to be kicked because of failed antibot verification.
|
||||||
|
*
|
||||||
|
* @param name the name to add
|
||||||
|
*/
|
||||||
|
public void addPlayerKick(String name) {
|
||||||
|
antibotKicked.addIfAbsent(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
public enum AntiBotStatus {
|
public enum AntiBotStatus {
|
||||||
LISTENING,
|
LISTENING,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
|
|||||||
@ -1,146 +1,95 @@
|
|||||||
package fr.xephi.authme;
|
package fr.xephi.authme;
|
||||||
|
|
||||||
|
import ch.jalu.injector.Injector;
|
||||||
|
import ch.jalu.injector.InjectorBuilder;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import fr.xephi.authme.api.API;
|
import fr.xephi.authme.api.API;
|
||||||
import fr.xephi.authme.api.NewAPI;
|
import fr.xephi.authme.api.NewAPI;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.cache.backup.JsonCache;
|
|
||||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
|
||||||
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
|
||||||
import fr.xephi.authme.command.CommandHandler;
|
import fr.xephi.authme.command.CommandHandler;
|
||||||
import fr.xephi.authme.datasource.CacheDataSource;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.datasource.DataSourceType;
|
|
||||||
import fr.xephi.authme.datasource.FlatFile;
|
|
||||||
import fr.xephi.authme.datasource.MySQL;
|
|
||||||
import fr.xephi.authme.datasource.SQLite;
|
|
||||||
import fr.xephi.authme.hooks.BungeeCordMessage;
|
|
||||||
import fr.xephi.authme.hooks.PluginHooks;
|
|
||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.initialization.MetricsStarter;
|
import fr.xephi.authme.initialization.Initializer;
|
||||||
import fr.xephi.authme.listener.AuthMeBlockListener;
|
import fr.xephi.authme.initialization.MetricsManager;
|
||||||
import fr.xephi.authme.listener.AuthMeEntityListener;
|
import fr.xephi.authme.initialization.OnShutdownPlayerSaver;
|
||||||
import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter;
|
import fr.xephi.authme.initialization.TaskCloser;
|
||||||
import fr.xephi.authme.listener.AuthMePlayerListener;
|
import fr.xephi.authme.listener.BlockListener;
|
||||||
import fr.xephi.authme.listener.AuthMePlayerListener16;
|
import fr.xephi.authme.listener.EntityListener;
|
||||||
import fr.xephi.authme.listener.AuthMePlayerListener18;
|
import fr.xephi.authme.listener.PlayerListener;
|
||||||
import fr.xephi.authme.listener.AuthMeServerListener;
|
import fr.xephi.authme.listener.PlayerListener16;
|
||||||
import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter;
|
import fr.xephi.authme.listener.PlayerListener18;
|
||||||
import fr.xephi.authme.listener.AuthMeTablistPacketAdapter;
|
import fr.xephi.authme.listener.PlayerListener19;
|
||||||
import fr.xephi.authme.mail.SendMailSSL;
|
import fr.xephi.authme.listener.ServerListener;
|
||||||
import fr.xephi.authme.output.ConsoleFilter;
|
|
||||||
import fr.xephi.authme.output.Log4JFilter;
|
|
||||||
import fr.xephi.authme.output.MessageKey;
|
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
|
||||||
import fr.xephi.authme.security.crypts.SHA256;
|
import fr.xephi.authme.security.crypts.SHA256;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.SettingsMigrationService;
|
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
|
||||||
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.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.PurgeSettings;
|
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
|
import fr.xephi.authme.task.CleanupTask;
|
||||||
import fr.xephi.authme.settings.propertymap.PropertyMap;
|
import fr.xephi.authme.task.purge.PurgeService;
|
||||||
import fr.xephi.authme.task.PurgeTask;
|
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import fr.xephi.authme.util.FileUtils;
|
|
||||||
import fr.xephi.authme.util.GeoLiteAPI;
|
import fr.xephi.authme.util.GeoLiteAPI;
|
||||||
import fr.xephi.authme.util.MigrationService;
|
import fr.xephi.authme.util.MigrationService;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
|
import org.bukkit.plugin.PluginLoader;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
|
import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
|
||||||
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
|
import static fr.xephi.authme.util.Utils.isClassLoaded;
|
||||||
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The AuthMe main class.
|
* The AuthMe main class.
|
||||||
*/
|
*/
|
||||||
public class AuthMe extends JavaPlugin {
|
public class AuthMe extends JavaPlugin {
|
||||||
|
|
||||||
// Defines the name of the plugin.
|
// Constants
|
||||||
private static final String PLUGIN_NAME = "AuthMeReloaded";
|
private static final String PLUGIN_NAME = "AuthMeReloaded";
|
||||||
|
private static final String LOG_FILENAME = "authme.log";
|
||||||
|
private static final int CLEANUP_INTERVAL = 5 * TICKS_PER_MINUTE;
|
||||||
|
|
||||||
// Default version and build number values;
|
// Default version and build number values;
|
||||||
private static String pluginVersion = "N/D";
|
private static String pluginVersion = "N/D";
|
||||||
private static String pluginBuildNumber = "Unknown";
|
private static String pluginBuildNumber = "Unknown";
|
||||||
|
|
||||||
// Private Instances
|
// Private instances
|
||||||
private static AuthMe plugin;
|
|
||||||
/*
|
|
||||||
* Maps and stuff
|
|
||||||
*/
|
|
||||||
public final ConcurrentHashMap<String, BukkitTask> sessions = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public instances
|
|
||||||
*/
|
|
||||||
public NewAPI api;
|
|
||||||
// TODO #655: Encapsulate mail
|
|
||||||
public SendMailSSL mail;
|
|
||||||
// TODO #656: Encapsulate data manager
|
|
||||||
public DataManager dataManager;
|
|
||||||
/*
|
|
||||||
* Private instances
|
|
||||||
*/
|
|
||||||
// TODO #604: Encapsulate ProtocolLib members
|
|
||||||
public AuthMeInventoryPacketAdapter inventoryProtector;
|
|
||||||
public AuthMeTabCompletePacketAdapter tabComplete;
|
|
||||||
public AuthMeTablistPacketAdapter tablistHider;
|
|
||||||
private Management management;
|
|
||||||
private CommandHandler commandHandler;
|
private CommandHandler commandHandler;
|
||||||
private PermissionsManager permsMan;
|
private PermissionsManager permsMan;
|
||||||
private NewSetting newSettings;
|
private Settings settings;
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
private JsonCache playerBackup;
|
|
||||||
private PasswordSecurity passwordSecurity;
|
|
||||||
private DataSource database;
|
private DataSource database;
|
||||||
private PluginHooks pluginHooks;
|
|
||||||
private SpawnLoader spawnLoader;
|
|
||||||
private boolean autoPurging;
|
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
private AuthMeServiceInitializer initializer;
|
private Injector injector;
|
||||||
|
private GeoLiteAPI geoLiteApi;
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the plugin's instance.
|
* Constructor.
|
||||||
*
|
|
||||||
* @return AuthMe
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public AuthMe() {
|
||||||
public static AuthMe getInstance() {
|
}
|
||||||
return plugin;
|
|
||||||
|
/*
|
||||||
|
* Constructor for unit testing.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
@SuppressWarnings("deprecation") // the super constructor is deprecated to mark it for unit testing only
|
||||||
|
protected AuthMe(final PluginLoader loader, final Server server, final PluginDescriptionFile description,
|
||||||
|
final File dataFolder, final File file) {
|
||||||
|
super(loader, server, description, dataFolder, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,8 +119,100 @@ public class AuthMe extends JavaPlugin {
|
|||||||
return pluginBuildNumber;
|
return pluginBuildNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when the server enables the plugin.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
try {
|
||||||
|
initializeServices();
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Aborting initialization of AuthMe:", e);
|
||||||
|
stopOrUnload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show settings warnings
|
||||||
|
showSettingsWarnings();
|
||||||
|
|
||||||
|
// If server is using PermissionsBukkit, print a warning that some features may not be supported
|
||||||
|
if (PermissionsSystemType.PERMISSIONS_BUKKIT.equals(permsMan.getPermissionSystem())) {
|
||||||
|
ConsoleLogger.warning("Warning! This server uses PermissionsBukkit for permissions. Some permissions features may not be supported!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a backup on start
|
||||||
|
new PerformBackup(this, settings).doBackup(PerformBackup.BackupCause.START);
|
||||||
|
|
||||||
|
// Set up Metrics
|
||||||
|
MetricsManager.sendMetrics(this, settings);
|
||||||
|
|
||||||
|
// Sponsor messages
|
||||||
|
ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt.");
|
||||||
|
ConsoleLogger.info("Do you want a good game server? Look at our sponsor GameHosting.it leader in Italy as Game Server Provider!");
|
||||||
|
|
||||||
|
// Successful message
|
||||||
|
ConsoleLogger.info("AuthMe " + getPluginVersion() + " build n°" + getPluginBuildNumber() + " correctly enabled!");
|
||||||
|
|
||||||
|
// Purge on start if enabled
|
||||||
|
PurgeService purgeService = injector.getSingleton(PurgeService.class);
|
||||||
|
purgeService.runAutoPurge();
|
||||||
|
|
||||||
|
// Schedule clean up task
|
||||||
|
CleanupTask cleanupTask = injector.getSingleton(CleanupTask.class);
|
||||||
|
cleanupTask.runTaskTimerAsynchronously(this, CLEANUP_INTERVAL, CLEANUP_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeServices() throws Exception {
|
||||||
|
// Set the plugin instance and load plugin info from the plugin description.
|
||||||
|
loadPluginInfo();
|
||||||
|
|
||||||
|
// Set the Logger instance and log file path
|
||||||
|
ConsoleLogger.setLogger(getLogger());
|
||||||
|
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
|
||||||
|
|
||||||
|
bukkitService = new BukkitService(this);
|
||||||
|
Initializer initializer = new Initializer(this, bukkitService);
|
||||||
|
|
||||||
|
// Load settings and set up the console and console filter
|
||||||
|
settings = initializer.createSettings();
|
||||||
|
ConsoleLogger.setLoggingOptions(settings);
|
||||||
|
initializer.setupConsoleFilter(settings, getLogger());
|
||||||
|
|
||||||
|
// Connect to the database and set up tables
|
||||||
|
database = initializer.setupDatabase(settings);
|
||||||
|
|
||||||
|
// Convert deprecated PLAINTEXT hash entries
|
||||||
|
MigrationService.changePlainTextToSha256(settings, database, new SHA256());
|
||||||
|
|
||||||
|
// Injector initialization
|
||||||
|
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
|
||||||
|
|
||||||
|
// Register elements of the Bukkit / JavaPlugin environment
|
||||||
|
injector.register(AuthMe.class, this);
|
||||||
|
injector.register(Server.class, getServer());
|
||||||
|
injector.register(PluginManager.class, getServer().getPluginManager());
|
||||||
|
injector.register(BukkitScheduler.class, getServer().getScheduler());
|
||||||
|
injector.provide(DataFolder.class, getDataFolder());
|
||||||
|
|
||||||
|
// Register elements we instantiate manually
|
||||||
|
injector.register(Settings.class, settings);
|
||||||
|
injector.register(DataSource.class, database);
|
||||||
|
injector.register(BukkitService.class, bukkitService);
|
||||||
|
|
||||||
|
instantiateServices(injector);
|
||||||
|
|
||||||
|
// Reload support hook
|
||||||
|
reloadSupportHook();
|
||||||
|
|
||||||
|
// Register event listeners
|
||||||
|
registerEventListeners(injector);
|
||||||
|
|
||||||
|
// Start Email recall task if needed
|
||||||
|
initializer.scheduleRecallEmailTask(settings, database, messages);
|
||||||
|
}
|
||||||
|
|
||||||
// Get version and build number of the plugin
|
// Get version and build number of the plugin
|
||||||
private void setPluginInfos() {
|
private void loadPluginInfo() {
|
||||||
String versionRaw = this.getDescription().getVersion();
|
String versionRaw = this.getDescription().getVersion();
|
||||||
int index = versionRaw.lastIndexOf("-");
|
int index = versionRaw.lastIndexOf("-");
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
@ -184,136 +225,24 @@ public class AuthMe extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called when the server enables the plugin.
|
* Instantiates all services.
|
||||||
|
*
|
||||||
|
* @param injector the injector
|
||||||
*/
|
*/
|
||||||
@Override
|
protected void instantiateServices(Injector injector) {
|
||||||
public void onEnable() {
|
// PlayerCache is still injected statically sometimes
|
||||||
// Set various instances
|
playerCache = PlayerCache.getInstance();
|
||||||
plugin = this;
|
injector.register(PlayerCache.class, playerCache);
|
||||||
ConsoleLogger.setLogger(getLogger());
|
|
||||||
setPluginInfos();
|
|
||||||
|
|
||||||
// Load settings and custom configurations, if it fails, stop the server due to security reasons.
|
messages = injector.getSingleton(Messages.class);
|
||||||
newSettings = createNewSetting();
|
permsMan = injector.getSingleton(PermissionsManager.class);
|
||||||
if (newSettings == null) {
|
bukkitService = injector.getSingleton(BukkitService.class);
|
||||||
getLogger().warning("Could not load configuration. Aborting.");
|
commandHandler = injector.getSingleton(CommandHandler.class);
|
||||||
getServer().shutdown();
|
geoLiteApi = injector.getSingleton(GeoLiteAPI.class);
|
||||||
return;
|
|
||||||
}
|
|
||||||
ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log"));
|
|
||||||
ConsoleLogger.setLoggingOptions(newSettings);
|
|
||||||
|
|
||||||
// Old settings manager
|
// Trigger construction of API classes; they will keep track of the singleton
|
||||||
if (!loadSettings()) {
|
injector.getSingleton(NewAPI.class);
|
||||||
getServer().shutdown();
|
injector.getSingleton(API.class);
|
||||||
setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages = new Messages(newSettings.getMessagesFile(), newSettings.getDefaultMessagesFile());
|
|
||||||
|
|
||||||
// Connect to the database and setup tables
|
|
||||||
try {
|
|
||||||
setupDatabase(newSettings);
|
|
||||||
} catch (Exception e) {
|
|
||||||
ConsoleLogger.logException("Fatal error occurred during database connection! "
|
|
||||||
+ "Authme initialization aborted!", e);
|
|
||||||
stopOrUnload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MigrationService.changePlainTextToSha256(newSettings, database, new SHA256());
|
|
||||||
|
|
||||||
|
|
||||||
initializer = new AuthMeServiceInitializer("fr.xephi.authme");
|
|
||||||
// Register elements of the Bukkit / JavaPlugin environment
|
|
||||||
initializer.register(AuthMe.class, this);
|
|
||||||
initializer.register(Server.class, getServer());
|
|
||||||
initializer.register(PluginManager.class, getServer().getPluginManager());
|
|
||||||
initializer.register(BukkitScheduler.class, getServer().getScheduler());
|
|
||||||
initializer.provide(DataFolder.class, getDataFolder());
|
|
||||||
|
|
||||||
// Register elements we instantiate manually
|
|
||||||
initializer.register(NewSetting.class, newSettings);
|
|
||||||
initializer.register(Messages.class, messages);
|
|
||||||
initializer.register(DataSource.class, database);
|
|
||||||
|
|
||||||
// Some statically injected things
|
|
||||||
initializer.register(PlayerCache.class, PlayerCache.getInstance());
|
|
||||||
|
|
||||||
// Note ljacqu 20160612: Instantiate LimboCache first to make sure it is instantiated
|
|
||||||
// (because sometimes it's used via LimboCache.getInstance())
|
|
||||||
// Once LimboCache#getInstance() no longer exists this can be removed!
|
|
||||||
initializer.get(LimboCache.class);
|
|
||||||
|
|
||||||
permsMan = initializer.get(PermissionsManager.class);
|
|
||||||
bukkitService = initializer.get(BukkitService.class);
|
|
||||||
pluginHooks = initializer.get(PluginHooks.class);
|
|
||||||
passwordSecurity = initializer.get(PasswordSecurity.class);
|
|
||||||
spawnLoader = initializer.get(SpawnLoader.class);
|
|
||||||
commandHandler = initializer.get(CommandHandler.class);
|
|
||||||
api = initializer.get(NewAPI.class);
|
|
||||||
management = initializer.get(Management.class);
|
|
||||||
dataManager = initializer.get(DataManager.class);
|
|
||||||
initializer.get(API.class);
|
|
||||||
|
|
||||||
// Set up Metrics
|
|
||||||
MetricsStarter.setupMetrics(this, newSettings);
|
|
||||||
|
|
||||||
// Set console filter
|
|
||||||
setupConsoleFilter();
|
|
||||||
|
|
||||||
// Download and load GeoIp.dat file if absent
|
|
||||||
GeoLiteAPI.isDataAvailable();
|
|
||||||
|
|
||||||
// Set up the mail API
|
|
||||||
setupMailApi();
|
|
||||||
|
|
||||||
// Check if the ProtocolLib is available. If so we could listen for
|
|
||||||
// inventory protection
|
|
||||||
checkProtocolLib();
|
|
||||||
// End of Hooks
|
|
||||||
|
|
||||||
// Do a backup on start
|
|
||||||
new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START);
|
|
||||||
|
|
||||||
|
|
||||||
// Setup the inventory backup
|
|
||||||
playerBackup = new JsonCache();
|
|
||||||
|
|
||||||
|
|
||||||
// Set up the BungeeCord hook
|
|
||||||
setupBungeeCordHook(newSettings, initializer);
|
|
||||||
|
|
||||||
// Reload support hook
|
|
||||||
reloadSupportHook();
|
|
||||||
|
|
||||||
// Register event listeners
|
|
||||||
registerEventListeners(initializer);
|
|
||||||
// Start Email recall task if needed
|
|
||||||
scheduleRecallEmailTask();
|
|
||||||
|
|
||||||
// Show settings warnings
|
|
||||||
showSettingsWarnings();
|
|
||||||
|
|
||||||
// Sponsor messages
|
|
||||||
ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt.");
|
|
||||||
ConsoleLogger.info("Do you want a good game server? Look at our sponsor GameHosting.it leader in Italy as Game Server Provider!");
|
|
||||||
|
|
||||||
// Successful message
|
|
||||||
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!");
|
|
||||||
|
|
||||||
// Purge on start if enabled
|
|
||||||
runAutoPurge();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the mail API, if enabled.
|
|
||||||
*/
|
|
||||||
private void setupMailApi() {
|
|
||||||
// Make sure the mail API is enabled
|
|
||||||
if (!newSettings.getProperty(MAIL_ACCOUNT).isEmpty() && !newSettings.getProperty(MAIL_PASSWORD).isEmpty()) {
|
|
||||||
this.mail = new SendMailSSL(this, newSettings);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,370 +250,105 @@ public class AuthMe extends JavaPlugin {
|
|||||||
*/
|
*/
|
||||||
private void showSettingsWarnings() {
|
private void showSettingsWarnings() {
|
||||||
// Force single session disabled
|
// Force single session disabled
|
||||||
if (!newSettings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) {
|
if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) {
|
||||||
ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!");
|
ConsoleLogger.warning("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session timeout disabled
|
// Session timeout disabled
|
||||||
if (newSettings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0
|
if (settings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0
|
||||||
&& newSettings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
&& settings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
||||||
ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!");
|
ConsoleLogger.warning("WARNING!!! You set session timeout to 0, this may cause security issues!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register all event listeners.
|
* Registers all event listeners.
|
||||||
|
*
|
||||||
|
* @param injector the injector
|
||||||
*/
|
*/
|
||||||
private void registerEventListeners(AuthMeServiceInitializer initializer) {
|
protected void registerEventListeners(Injector injector) {
|
||||||
// Get the plugin manager instance
|
// Get the plugin manager instance
|
||||||
PluginManager pluginManager = getServer().getPluginManager();
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
|
|
||||||
// Register event listeners
|
// Register event listeners
|
||||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this);
|
pluginManager.registerEvents(injector.getSingleton(PlayerListener.class), this);
|
||||||
pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this);
|
pluginManager.registerEvents(injector.getSingleton(BlockListener.class), this);
|
||||||
pluginManager.registerEvents(initializer.get(AuthMeEntityListener.class), this);
|
pluginManager.registerEvents(injector.getSingleton(EntityListener.class), this);
|
||||||
pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this);
|
pluginManager.registerEvents(injector.getSingleton(ServerListener.class), this);
|
||||||
|
|
||||||
// Try to register 1.6 player listeners
|
// Try to register 1.6 player listeners
|
||||||
try {
|
if (isClassLoaded("org.bukkit.event.player.PlayerEditBookEvent")) {
|
||||||
Class.forName("org.bukkit.event.player.PlayerEditBookEvent");
|
pluginManager.registerEvents(injector.getSingleton(PlayerListener16.class), this);
|
||||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener16.class), this);
|
|
||||||
} catch (ClassNotFoundException ignore) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to register 1.8 player listeners
|
// Try to register 1.8 player listeners
|
||||||
try {
|
if (isClassLoaded("org.bukkit.event.player.PlayerInteractAtEntityEvent")) {
|
||||||
Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent");
|
pluginManager.registerEvents(injector.getSingleton(PlayerListener18.class), this);
|
||||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener18.class), this);
|
}
|
||||||
} catch (ClassNotFoundException ignore) {
|
|
||||||
|
// Try to register 1.9 player listeners
|
||||||
|
if (isClassLoaded("org.bukkit.event.player.PlayerSwapHandItemsEvent")) {
|
||||||
|
pluginManager.registerEvents(injector.getSingleton(PlayerListener19.class), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the server or disables the plugin, as defined in the configuration.
|
||||||
|
*/
|
||||||
|
public void stopOrUnload() {
|
||||||
|
if (settings == null || settings.getProperty(SecuritySettings.STOP_SERVER_ON_PROBLEM)) {
|
||||||
|
ConsoleLogger.warning("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!");
|
||||||
|
setEnabled(false);
|
||||||
|
getServer().shutdown();
|
||||||
|
} else {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check this, do we really need it? -sgdc3
|
||||||
private void reloadSupportHook() {
|
private void reloadSupportHook() {
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
int playersOnline = bukkitService.getOnlinePlayers().size();
|
int playersOnline = bukkitService.getOnlinePlayers().size();
|
||||||
if (playersOnline < 1) {
|
if (playersOnline == 0) {
|
||||||
database.purgeLogged();
|
database.purgeLogged();
|
||||||
} else if (Settings.reloadSupport) {
|
} else if (settings.getProperty(SecuritySettings.USE_RELOAD_COMMAND_SUPPORT)) {
|
||||||
for (PlayerAuth auth : database.getLoggedPlayers()) {
|
for (PlayerAuth auth : database.getLoggedPlayers()) {
|
||||||
if (auth == null) {
|
if (auth != null) {
|
||||||
continue;
|
auth.setLastLogin(new Date().getTime());
|
||||||
|
database.updateSession(auth);
|
||||||
|
playerCache.addPlayer(auth);
|
||||||
}
|
}
|
||||||
auth.setLastLogin(new Date().getTime());
|
|
||||||
database.updateSession(auth);
|
|
||||||
PlayerCache.getInstance().addPlayer(auth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the BungeeCord hook.
|
|
||||||
*/
|
|
||||||
private void setupBungeeCordHook(NewSetting settings, AuthMeServiceInitializer initializer) {
|
|
||||||
if (settings.getProperty(HooksSettings.BUNGEECORD)) {
|
|
||||||
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
|
||||||
Bukkit.getMessenger().registerIncomingPluginChannel(
|
|
||||||
this, "BungeeCord", initializer.get(BungeeCordMessage.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the plugin's settings.
|
|
||||||
*
|
|
||||||
* @return True on success, false on failure.
|
|
||||||
*/
|
|
||||||
private boolean loadSettings() {
|
|
||||||
try {
|
|
||||||
new Settings(this);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
ConsoleLogger.logException("Can't load the configuration file... Something went wrong. "
|
|
||||||
+ "To avoid security issues the server will shut down!", e);
|
|
||||||
getServer().shutdown();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NewSetting createNewSetting() {
|
|
||||||
File configFile = new File(getDataFolder(), "config.yml");
|
|
||||||
PropertyMap properties = SettingsFieldRetriever.getAllPropertyFields();
|
|
||||||
SettingsMigrationService migrationService = new SettingsMigrationService();
|
|
||||||
return FileUtils.copyFileFromResource(configFile, "config.yml")
|
|
||||||
? new NewSetting(configFile, getDataFolder(), properties, migrationService)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the console filter.
|
|
||||||
*/
|
|
||||||
private void setupConsoleFilter() {
|
|
||||||
if (newSettings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
|
|
||||||
ConsoleFilter filter = new ConsoleFilter();
|
|
||||||
getLogger().setFilter(filter);
|
|
||||||
Bukkit.getLogger().setFilter(filter);
|
|
||||||
Logger.getLogger("Minecraft").setFilter(filter);
|
|
||||||
// Set Log4J Filter
|
|
||||||
try {
|
|
||||||
Class.forName("org.apache.logging.log4j.core.Filter");
|
|
||||||
setLog4JFilter();
|
|
||||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
|
||||||
ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
// Save player data
|
// onDisable is also called when we prematurely abort, so any field may be null
|
||||||
BukkitService bukkitService = initializer.getIfAvailable(BukkitService.class);
|
OnShutdownPlayerSaver onShutdownPlayerSaver = injector == null
|
||||||
LimboCache limboCache = initializer.getIfAvailable(LimboCache.class);
|
? null
|
||||||
|
: injector.createIfHasDependencies(OnShutdownPlayerSaver.class);
|
||||||
if (bukkitService != null && limboCache != null) {
|
if (onShutdownPlayerSaver != null) {
|
||||||
Collection<? extends Player> players = bukkitService.getOnlinePlayers();
|
onShutdownPlayerSaver.saveAllPlayers();
|
||||||
for (Player player : players) {
|
|
||||||
savePlayer(player, limboCache);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do backup on stop if enabled
|
// Do backup on stop if enabled
|
||||||
if (newSettings != null) {
|
if (settings != null) {
|
||||||
new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.STOP);
|
new PerformBackup(this, settings).doBackup(PerformBackup.BackupCause.STOP);
|
||||||
}
|
}
|
||||||
final AuthMe pluginInstance = this;
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
List<Integer> pendingTasks = new ArrayList<>();
|
|
||||||
for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) {
|
|
||||||
if (pendingTask.getOwner().equals(pluginInstance) && !pendingTask.isSync()) {
|
|
||||||
pendingTasks.add(pendingTask.getTaskId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getLogger().info("Waiting for " + pendingTasks.size() + " tasks to finish");
|
|
||||||
int progress = 0;
|
|
||||||
for (int taskId : pendingTasks) {
|
|
||||||
int maxTries = 5;
|
|
||||||
while (getServer().getScheduler().isCurrentlyRunning(taskId)) {
|
|
||||||
if (maxTries <= 0) {
|
|
||||||
getLogger().info("Async task " + taskId + " times out after to many tries");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
maxTries--;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress++;
|
// Wait for tasks and close data source
|
||||||
getLogger().info("Progress: " + progress + " / " + pendingTasks.size());
|
new Thread(
|
||||||
}
|
new TaskCloser(this, database),
|
||||||
if (database != null) {
|
"AuthMe-DataSource#close"
|
||||||
database.close();
|
).start();
|
||||||
}
|
|
||||||
}
|
|
||||||
}, "AuthMe-DataSource#close").start();
|
|
||||||
|
|
||||||
// Disabled correctly
|
// Disabled correctly
|
||||||
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
|
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
|
||||||
ConsoleLogger.close();
|
ConsoleLogger.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop/unload the server/plugin as defined in the configuration
|
|
||||||
public void stopOrUnload() {
|
|
||||||
if (Settings.isStopEnabled) {
|
|
||||||
ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!");
|
|
||||||
getServer().shutdown();
|
|
||||||
} else {
|
|
||||||
getServer().getPluginManager().disablePlugin(AuthMe.getInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the data source.
|
|
||||||
*
|
|
||||||
* @param settings The settings instance
|
|
||||||
*
|
|
||||||
* @throws ClassNotFoundException if no driver could be found for the datasource
|
|
||||||
* @throws SQLException when initialization of a SQL datasource failed
|
|
||||||
* @see AuthMe#database
|
|
||||||
*/
|
|
||||||
public void setupDatabase(NewSetting settings) throws ClassNotFoundException, SQLException {
|
|
||||||
if (this.database != null) {
|
|
||||||
this.database.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
|
|
||||||
DataSource dataSource;
|
|
||||||
switch (dataSourceType) {
|
|
||||||
case FILE:
|
|
||||||
dataSource = new FlatFile();
|
|
||||||
break;
|
|
||||||
case MYSQL:
|
|
||||||
dataSource = new MySQL(settings);
|
|
||||||
break;
|
|
||||||
case SQLITE:
|
|
||||||
dataSource = new SQLite(settings);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
DataSource convertedSource = MigrationService.convertFlatfileToSqlite(newSettings, dataSource);
|
|
||||||
dataSource = convertedSource == null ? dataSource : convertedSource;
|
|
||||||
|
|
||||||
if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) {
|
|
||||||
dataSource = new CacheDataSource(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
database = dataSource;
|
|
||||||
if (DataSourceType.SQLITE == dataSourceType) {
|
|
||||||
getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int accounts = database.getAccountsRegistered();
|
|
||||||
if (accounts >= 4000) {
|
|
||||||
ConsoleLogger.showError("YOU'RE USING THE SQLITE DATABASE WITH "
|
|
||||||
+ accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the console filter to remove the passwords
|
|
||||||
private void setLog4JFilter() {
|
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
org.apache.logging.log4j.core.Logger logger;
|
|
||||||
logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
|
|
||||||
logger.addFilter(new Log4JFilter());
|
|
||||||
logger = (org.apache.logging.log4j.core.Logger) LogManager.getLogger("net.minecraft");
|
|
||||||
logger.addFilter(new Log4JFilter());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the presence of the ProtocolLib plugin
|
|
||||||
public void checkProtocolLib() {
|
|
||||||
if (!getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
|
|
||||||
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
|
||||||
ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
|
|
||||||
Settings.protectInventoryBeforeLogInEnabled = false;
|
|
||||||
newSettings.setProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN, false);
|
|
||||||
newSettings.save();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN) && inventoryProtector == null) {
|
|
||||||
inventoryProtector = new AuthMeInventoryPacketAdapter(this);
|
|
||||||
inventoryProtector.register();
|
|
||||||
} else if (inventoryProtector != null) {
|
|
||||||
inventoryProtector.unregister();
|
|
||||||
inventoryProtector = null;
|
|
||||||
}
|
|
||||||
if (newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN) && tabComplete == null) {
|
|
||||||
tabComplete = new AuthMeTabCompletePacketAdapter(this);
|
|
||||||
tabComplete.register();
|
|
||||||
} else if (tabComplete != null) {
|
|
||||||
tabComplete.unregister();
|
|
||||||
tabComplete = null;
|
|
||||||
}
|
|
||||||
if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) {
|
|
||||||
tablistHider = new AuthMeTablistPacketAdapter(this, bukkitService);
|
|
||||||
tablistHider.register();
|
|
||||||
} else if (tablistHider != null) {
|
|
||||||
tablistHider.unregister();
|
|
||||||
tablistHider = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save Player Data
|
|
||||||
private void savePlayer(Player player, LimboCache limboCache) {
|
|
||||||
if (safeIsNpc(player) || Utils.isUnrestricted(player)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
if (PlayerCache.getInstance().isAuthenticated(name) && !player.isDead() && Settings.isSaveQuitLocationEnabled) {
|
|
||||||
final PlayerAuth auth = PlayerAuth.builder()
|
|
||||||
.name(player.getName().toLowerCase())
|
|
||||||
.realName(player.getName())
|
|
||||||
.location(player.getLocation()).build();
|
|
||||||
database.updateQuitLoc(auth);
|
|
||||||
}
|
|
||||||
if (limboCache.hasLimboPlayer(name)) {
|
|
||||||
LimboPlayer limbo = limboCache.getLimboPlayer(name);
|
|
||||||
if (!Settings.noTeleport) {
|
|
||||||
player.teleport(limbo.getLoc());
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils.addNormal(player, limbo.getGroup());
|
|
||||||
player.setOp(limbo.isOperator());
|
|
||||||
limbo.getTimeoutTask().cancel();
|
|
||||||
limboCache.deleteLimboPlayer(name);
|
|
||||||
if (this.playerBackup.doesCacheExist(player)) {
|
|
||||||
this.playerBackup.removeCache(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlayerCache.getInstance().removePlayer(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean safeIsNpc(Player player) {
|
|
||||||
return pluginHooks != null && pluginHooks.isNpc(player) || player.hasMetadata("NPC");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge inactive players from the database, as defined in the configuration
|
|
||||||
private void runAutoPurge() {
|
|
||||||
if (!newSettings.getProperty(PurgeSettings.USE_AUTO_PURGE) || autoPurging) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoPurging = true;
|
|
||||||
|
|
||||||
ConsoleLogger.info("AutoPurging the Database...");
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
|
||||||
calendar.add(Calendar.DATE, -newSettings.getProperty(PurgeSettings.DAYS_BEFORE_REMOVE_PLAYER));
|
|
||||||
long until = calendar.getTimeInMillis();
|
|
||||||
Set<String> cleared = database.autoPurgeDatabase(until);
|
|
||||||
if (CollectionUtils.isEmpty(cleared)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!");
|
|
||||||
ConsoleLogger.info("Purging user accounts...");
|
|
||||||
new PurgeTask(plugin, Bukkit.getConsoleSender(), cleared, true, Bukkit.getOfflinePlayers())
|
|
||||||
.runTaskTimer(plugin, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the spawn location of a player
|
|
||||||
@Deprecated
|
|
||||||
public Location getSpawnLocation(Player player) {
|
|
||||||
return spawnLoader.getSpawnLocation(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduleRecallEmailTask() {
|
|
||||||
if (!newSettings.getProperty(RECALL_PLAYERS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
for (PlayerAuth auth : database.getLoggedPlayers()) {
|
|
||||||
String email = auth.getEmail();
|
|
||||||
if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
|
|
||||||
Player player = bukkitService.getPlayerExact(auth.getRealName());
|
|
||||||
if (player != null) {
|
|
||||||
messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 1, 1200 * newSettings.getProperty(EmailSettings.DELAY_RECALL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String replaceAllInfo(String message, Player player) {
|
public String replaceAllInfo(String message, Player player) {
|
||||||
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
|
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
|
||||||
String ipAddress = Utils.getPlayerIp(player);
|
String ipAddress = Utils.getPlayerIp(player);
|
||||||
@ -695,15 +359,15 @@ public class AuthMe extends JavaPlugin {
|
|||||||
.replace("{ONLINE}", playersOnline)
|
.replace("{ONLINE}", playersOnline)
|
||||||
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
|
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
|
||||||
.replace("{IP}", ipAddress)
|
.replace("{IP}", ipAddress)
|
||||||
.replace("{LOGINS}", Integer.toString(PlayerCache.getInstance().getLogged()))
|
.replace("{LOGINS}", Integer.toString(playerCache.getLogged()))
|
||||||
.replace("{WORLD}", player.getWorld().getName())
|
.replace("{WORLD}", player.getWorld().getName())
|
||||||
.replace("{SERVER}", server.getServerName())
|
.replace("{SERVER}", server.getServerName())
|
||||||
.replace("{VERSION}", server.getBukkitVersion())
|
.replace("{VERSION}", server.getBukkitVersion())
|
||||||
.replace("{COUNTRY}", GeoLiteAPI.getCountryName(ipAddress));
|
// TODO: We should cache info like this, maybe with a class that extends Player?
|
||||||
|
.replace("{COUNTRY}", geoLiteApi.getCountryName(ipAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Bukkit commands.
|
* Handle Bukkit commands.
|
||||||
*
|
*
|
||||||
@ -726,67 +390,4 @@ public class AuthMe extends JavaPlugin {
|
|||||||
// Handle the command
|
// Handle the command
|
||||||
return commandHandler.processCommand(sender, commandLabel, args);
|
return commandHandler.processCommand(sender, commandLabel, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyAutoPurgeEnd() {
|
|
||||||
this.autoPurging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------
|
|
||||||
// Service getters (deprecated)
|
|
||||||
// Use @Inject fields instead
|
|
||||||
// -------------
|
|
||||||
/**
|
|
||||||
* @return NewSetting
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public NewSetting getSettings() {
|
|
||||||
return newSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return permission manager
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public PermissionsManager getPermissionsManager() {
|
|
||||||
return this.permsMan;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return process manager
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Management getManagement() {
|
|
||||||
return management;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the datasource
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DataSource getDataSource() {
|
|
||||||
return database;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return password manager
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public PasswordSecurity getPasswordSecurity() {
|
|
||||||
return passwordSecurity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return plugin hooks
|
|
||||||
* @deprecated should be used in API classes only (temporarily)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public PluginHooks getPluginHooks() {
|
|
||||||
return pluginHooks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
package fr.xephi.authme;
|
package fr.xephi.authme;
|
||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.output.LogLevel;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
|
||||||
@ -11,7 +13,6 @@ import java.io.IOException;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +23,7 @@ public final class ConsoleLogger {
|
|||||||
private static final String NEW_LINE = System.getProperty("line.separator");
|
private static final String NEW_LINE = System.getProperty("line.separator");
|
||||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
|
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
|
||||||
private static Logger logger;
|
private static Logger logger;
|
||||||
private static boolean enableDebug = false;
|
private static LogLevel logLevel = LogLevel.INFO;
|
||||||
private static boolean useLogging = false;
|
private static boolean useLogging = false;
|
||||||
private static File logFile;
|
private static File logFile;
|
||||||
private static FileWriter fileWriter;
|
private static FileWriter fileWriter;
|
||||||
@ -30,17 +31,36 @@ public final class ConsoleLogger {
|
|||||||
private ConsoleLogger() {
|
private ConsoleLogger() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
// Configurations
|
||||||
|
// --------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the logger to use.
|
||||||
|
*
|
||||||
|
* @param logger The logger
|
||||||
|
*/
|
||||||
public static void setLogger(Logger logger) {
|
public static void setLogger(Logger logger) {
|
||||||
ConsoleLogger.logger = logger;
|
ConsoleLogger.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file to log to if enabled.
|
||||||
|
*
|
||||||
|
* @param logFile The log file
|
||||||
|
*/
|
||||||
public static void setLogFile(File logFile) {
|
public static void setLogFile(File logFile) {
|
||||||
ConsoleLogger.logFile = logFile;
|
ConsoleLogger.logFile = logFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setLoggingOptions(NewSetting settings) {
|
/**
|
||||||
|
* Load the required settings.
|
||||||
|
*
|
||||||
|
* @param settings The settings instance
|
||||||
|
*/
|
||||||
|
public static void setLoggingOptions(Settings settings) {
|
||||||
|
ConsoleLogger.logLevel = settings.getProperty(PluginSettings.LOG_LEVEL);
|
||||||
ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING);
|
ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING);
|
||||||
ConsoleLogger.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE);
|
|
||||||
if (useLogging) {
|
if (useLogging) {
|
||||||
if (fileWriter == null) {
|
if (fileWriter == null) {
|
||||||
try {
|
try {
|
||||||
@ -54,86 +74,81 @@ public final class ConsoleLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------
|
||||||
|
// Logging methods
|
||||||
|
// --------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print an info message.
|
* Log a WARN message.
|
||||||
*
|
*
|
||||||
* @param message String
|
* @param message The message to log
|
||||||
|
*/
|
||||||
|
public static void warning(String message) {
|
||||||
|
logger.warning(message);
|
||||||
|
writeLog("[WARN] " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an INFO message.
|
||||||
|
*
|
||||||
|
* @param message The message to log
|
||||||
*/
|
*/
|
||||||
public static void info(String message) {
|
public static void info(String message) {
|
||||||
logger.info(message);
|
logger.info(message);
|
||||||
if (useLogging) {
|
writeLog("[INFO] " + message);
|
||||||
writeLog(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a FINE message if enabled.
|
||||||
|
* <p>
|
||||||
|
* Implementation note: this logs a message on INFO level because
|
||||||
|
* levels below INFO are disabled by Bukkit/Spigot.
|
||||||
|
*
|
||||||
|
* @param message The message to log
|
||||||
|
*/
|
||||||
|
public static void fine(String message) {
|
||||||
|
if (logLevel.includes(LogLevel.FINE)) {
|
||||||
|
logger.info(message);
|
||||||
|
writeLog("[FINE] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a DEBUG message if enabled.
|
||||||
|
* <p>
|
||||||
|
* Implementation note: this logs a message on INFO level and prefixes it with "DEBUG" because
|
||||||
|
* levels below INFO are disabled by Bukkit/Spigot.
|
||||||
|
*
|
||||||
|
* @param message The message to log
|
||||||
|
*/
|
||||||
public static void debug(String message) {
|
public static void debug(String message) {
|
||||||
if (enableDebug) {
|
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||||
//creating and filling an exception is a expensive call
|
logger.info("Debug: " + message);
|
||||||
//TODO #419 20160601: ->so it should be removed as soon #419 is fixed
|
writeLog("[DEBUG] " + message);
|
||||||
//logger.isLoggable does not work because the plugin logger is always ALL
|
|
||||||
logger.log(Level.FINE, message + ' ' + Thread.currentThread().getName(), new Exception());
|
|
||||||
|
|
||||||
if (useLogging) {
|
|
||||||
writeLog("Debug: " + Thread.currentThread().getName() + ':' + message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print an error message.
|
* Log a Throwable with the provided message on WARNING level
|
||||||
*
|
* and save the stack trace to the log file.
|
||||||
* @param message String
|
|
||||||
*/
|
|
||||||
public static void showError(String message) {
|
|
||||||
logger.warning(message);
|
|
||||||
if (useLogging) {
|
|
||||||
writeLog("ERROR: " + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a message into the log file with a TimeStamp.
|
|
||||||
*
|
|
||||||
* @param message String
|
|
||||||
*/
|
|
||||||
private static void writeLog(String message) {
|
|
||||||
String dateTime;
|
|
||||||
synchronized (DATE_FORMAT) {
|
|
||||||
dateTime = DATE_FORMAT.format(new Date());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
fileWriter.write(dateTime);
|
|
||||||
fileWriter.write(": ");
|
|
||||||
fileWriter.write(message);
|
|
||||||
fileWriter.write(NEW_LINE);
|
|
||||||
fileWriter.flush();
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a StackTrace into the log.
|
|
||||||
*
|
|
||||||
* @param th The Throwable whose stack trace should be logged
|
|
||||||
*/
|
|
||||||
public static void writeStackTrace(Throwable th) {
|
|
||||||
if (useLogging) {
|
|
||||||
writeLog(Throwables.getStackTraceAsString(th));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a Throwable with the provided message and saves the stack trace to the log file.
|
|
||||||
*
|
*
|
||||||
* @param message The message to accompany the exception
|
* @param message The message to accompany the exception
|
||||||
* @param th The Throwable to log
|
* @param th The Throwable to log
|
||||||
*/
|
*/
|
||||||
public static void logException(String message, Throwable th) {
|
public static void logException(String message, Throwable th) {
|
||||||
showError(message + " " + StringUtils.formatException(th));
|
warning(message + " " + StringUtils.formatException(th));
|
||||||
writeStackTrace(th);
|
writeLog(Throwables.getStackTraceAsString(th));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------
|
||||||
|
// Helpers
|
||||||
|
// --------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all file handles.
|
||||||
|
*/
|
||||||
public static void close() {
|
public static void close() {
|
||||||
if (fileWriter != null) {
|
if (fileWriter != null) {
|
||||||
try {
|
try {
|
||||||
@ -144,4 +159,26 @@ public final class ConsoleLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a message into the log file with a TimeStamp if enabled.
|
||||||
|
*
|
||||||
|
* @param message The message to write to the log
|
||||||
|
*/
|
||||||
|
private static void writeLog(String message) {
|
||||||
|
if (useLogging) {
|
||||||
|
String dateTime;
|
||||||
|
synchronized (DATE_FORMAT) {
|
||||||
|
dateTime = DATE_FORMAT.format(new Date());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
fileWriter.write(dateTime);
|
||||||
|
fileWriter.write(": ");
|
||||||
|
fileWriter.write(message);
|
||||||
|
fileWriter.write(NEW_LINE);
|
||||||
|
fileWriter.flush();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package fr.xephi.authme;
|
package fr.xephi.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.datasource.DataSourceType;
|
import fr.xephi.authme.datasource.DataSourceType;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.BackupSettings;
|
import fr.xephi.authme.settings.properties.BackupSettings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
@ -30,7 +30,7 @@ public class PerformBackup {
|
|||||||
private final String tblname;
|
private final String tblname;
|
||||||
private final String path;
|
private final String path;
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
private final NewSetting settings;
|
private final Settings settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for PerformBackup.
|
* Constructor for PerformBackup.
|
||||||
@ -38,7 +38,7 @@ public class PerformBackup {
|
|||||||
* @param instance AuthMe
|
* @param instance AuthMe
|
||||||
* @param settings The plugin settings
|
* @param settings The plugin settings
|
||||||
*/
|
*/
|
||||||
public PerformBackup(AuthMe instance, NewSetting settings) {
|
public PerformBackup(AuthMe instance, Settings settings) {
|
||||||
this.dataFolder = instance.getDataFolder();
|
this.dataFolder = instance.getDataFolder();
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||||
@ -60,7 +60,7 @@ public class PerformBackup {
|
|||||||
if (!settings.getProperty(BackupSettings.ENABLED)) {
|
if (!settings.getProperty(BackupSettings.ENABLED)) {
|
||||||
// Print a warning if the backup was requested via command or by another plugin
|
// Print a warning if the backup was requested via command or by another plugin
|
||||||
if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) {
|
if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) {
|
||||||
ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
|
ConsoleLogger.warning("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
|
||||||
+ cause.name());
|
+ cause.name());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -76,7 +76,7 @@ public class PerformBackup {
|
|||||||
if (doBackup()) {
|
if (doBackup()) {
|
||||||
ConsoleLogger.info("A backup has been performed successfully. Cause of the Backup: " + cause.name());
|
ConsoleLogger.info("A backup has been performed successfully. Cause of the Backup: " + cause.name());
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.showError("Error while performing a backup! Cause of the Backup: " + cause.name());
|
ConsoleLogger.warning("Error while performing a backup! Cause of the Backup: " + cause.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ public class PerformBackup {
|
|||||||
case SQLITE:
|
case SQLITE:
|
||||||
return fileBackup(dbName + ".db");
|
return fileBackup(dbName + ".db");
|
||||||
default:
|
default:
|
||||||
ConsoleLogger.showError("Unknown data source type '" + dataSourceType + "' for backup");
|
ConsoleLogger.warning("Unknown data source type '" + dataSourceType + "' for backup");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -113,7 +113,7 @@ public class PerformBackup {
|
|||||||
ConsoleLogger.info("Backup created successfully.");
|
ConsoleLogger.info("Backup created successfully.");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.showError("Could not create the backup! (Windows)");
|
ConsoleLogger.warning("Could not create the backup! (Windows)");
|
||||||
}
|
}
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
ConsoleLogger.logException("Error during Windows backup:", e);
|
ConsoleLogger.logException("Error during Windows backup:", e);
|
||||||
@ -128,7 +128,7 @@ public class PerformBackup {
|
|||||||
ConsoleLogger.info("Backup created successfully.");
|
ConsoleLogger.info("Backup created successfully.");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.showError("Could not create the backup!");
|
ConsoleLogger.warning("Could not create the backup!");
|
||||||
}
|
}
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
ConsoleLogger.logException("Error during backup:", e);
|
ConsoleLogger.logException("Error during backup:", e);
|
||||||
@ -147,8 +147,7 @@ public class PerformBackup {
|
|||||||
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
|
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError("Encountered an error during file backup: " + StringUtils.formatException(ex));
|
ConsoleLogger.logException("Encountered an error during file backup:", ex);
|
||||||
ConsoleLogger.writeStackTrace(ex);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -166,7 +165,7 @@ public class PerformBackup {
|
|||||||
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
|
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.showError("Mysql Windows Path is incorrect. Please check it");
|
ConsoleLogger.warning("Mysql Windows Path is incorrect. Please check it");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,10 +4,11 @@ import fr.xephi.authme.AuthMe;
|
|||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -27,19 +28,21 @@ public class API {
|
|||||||
private static DataSource dataSource;
|
private static DataSource dataSource;
|
||||||
private static PasswordSecurity passwordSecurity;
|
private static PasswordSecurity passwordSecurity;
|
||||||
private static Management management;
|
private static Management management;
|
||||||
|
private static PluginHooks pluginHooks;
|
||||||
|
private static ValidationService validationService;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Constructor for the deprecated API.
|
* Constructor.
|
||||||
*
|
|
||||||
* @param instance AuthMe
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
@Inject
|
@Inject
|
||||||
API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management) {
|
API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management,
|
||||||
|
PluginHooks pluginHooks, ValidationService validationService) {
|
||||||
API.instance = instance;
|
API.instance = instance;
|
||||||
API.dataSource = dataSource;
|
API.dataSource = dataSource;
|
||||||
API.passwordSecurity = passwordSecurity;
|
API.passwordSecurity = passwordSecurity;
|
||||||
API.management = management;
|
API.management = management;
|
||||||
|
API.pluginHooks = pluginHooks;
|
||||||
|
API.validationService = validationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,7 +50,6 @@ public class API {
|
|||||||
*
|
*
|
||||||
* @return AuthMe instance
|
* @return AuthMe instance
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static AuthMe hookAuthMe() {
|
public static AuthMe hookAuthMe() {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
return instance;
|
return instance;
|
||||||
@ -66,7 +68,6 @@ public class API {
|
|||||||
* @param player The player to verify
|
* @param player The player to verify
|
||||||
* @return true if the player is authenticated
|
* @return true if the player is authenticated
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static boolean isAuthenticated(Player player) {
|
public static boolean isAuthenticated(Player player) {
|
||||||
return PlayerCache.getInstance().isAuthenticated(player.getName());
|
return PlayerCache.getInstance().isAuthenticated(player.getName());
|
||||||
}
|
}
|
||||||
@ -77,12 +78,10 @@ public class API {
|
|||||||
* @param player The player to verify
|
* @param player The player to verify
|
||||||
* @return true if the player is unrestricted
|
* @return true if the player is unrestricted
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static boolean isUnrestricted(Player player) {
|
public static boolean isUnrestricted(Player player) {
|
||||||
return Utils.isUnrestricted(player);
|
return validationService.isUnrestricted(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static Location getLastLocation(Player player) {
|
public static Location getLastLocation(Player player) {
|
||||||
try {
|
try {
|
||||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
|
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
|
||||||
@ -99,7 +98,6 @@ public class API {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static void setPlayerInventory(Player player, ItemStack[] content,
|
public static void setPlayerInventory(Player player, ItemStack[] content,
|
||||||
ItemStack[] armor) {
|
ItemStack[] armor) {
|
||||||
try {
|
try {
|
||||||
@ -115,7 +113,6 @@ public class API {
|
|||||||
* @param playerName The player name to verify
|
* @param playerName The player name to verify
|
||||||
* @return true if player is registered
|
* @return true if player is registered
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static boolean isRegistered(String playerName) {
|
public static boolean isRegistered(String playerName) {
|
||||||
String player = playerName.toLowerCase();
|
String player = playerName.toLowerCase();
|
||||||
return dataSource.isAuthAvailable(player);
|
return dataSource.isAuthAvailable(player);
|
||||||
@ -128,7 +125,6 @@ public class API {
|
|||||||
* @param passwordToCheck The password to check
|
* @param passwordToCheck The password to check
|
||||||
* @return true if the password is correct, false otherwise
|
* @return true if the password is correct, false otherwise
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static boolean checkPassword(String playerName, String passwordToCheck) {
|
public static boolean checkPassword(String playerName, String passwordToCheck) {
|
||||||
return isRegistered(playerName) && passwordSecurity.comparePassword(passwordToCheck, playerName);
|
return isRegistered(playerName) && passwordSecurity.comparePassword(passwordToCheck, playerName);
|
||||||
}
|
}
|
||||||
@ -140,7 +136,6 @@ public class API {
|
|||||||
* @param password The password
|
* @param password The password
|
||||||
* @return true if the player was registered correctly
|
* @return true if the player was registered correctly
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static boolean registerPlayer(String playerName, String password) {
|
public static boolean registerPlayer(String playerName, String password) {
|
||||||
String name = playerName.toLowerCase();
|
String name = playerName.toLowerCase();
|
||||||
HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
|
HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
|
||||||
@ -161,12 +156,10 @@ public class API {
|
|||||||
*
|
*
|
||||||
* @param player The player to log in
|
* @param player The player to log in
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static void forceLogin(Player player) {
|
public static void forceLogin(Player player) {
|
||||||
management.performLogin(player, "dontneed", true);
|
management.performLogin(player, "dontneed", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public AuthMe getPlugin() {
|
public AuthMe getPlugin() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -177,9 +170,8 @@ public class API {
|
|||||||
* @param player The player to verify
|
* @param player The player to verify
|
||||||
* @return true if player is an npc
|
* @return true if player is an npc
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public boolean isNPC(Player player) {
|
public boolean isNPC(Player player) {
|
||||||
return instance.getPluginHooks().isNpc(player);
|
return pluginHooks.isNpc(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,15 @@ package fr.xephi.authme.api;
|
|||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
|
import fr.xephi.authme.process.Management;
|
||||||
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -22,34 +25,41 @@ public class NewAPI {
|
|||||||
|
|
||||||
public static NewAPI singleton;
|
public static NewAPI singleton;
|
||||||
public final AuthMe plugin;
|
public final AuthMe plugin;
|
||||||
|
private final PluginHooks pluginHooks;
|
||||||
|
private final DataSource dataSource;
|
||||||
|
private final PasswordSecurity passwordSecurity;
|
||||||
|
private final Management management;
|
||||||
|
private final ValidationService validationService;
|
||||||
|
private final PlayerCache playerCache;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Constructor for NewAPI.
|
* Constructor for NewAPI.
|
||||||
*
|
|
||||||
* @param plugin The AuthMe plugin instance
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public NewAPI(AuthMe plugin) {
|
NewAPI(AuthMe plugin, PluginHooks pluginHooks, DataSource dataSource, PasswordSecurity passwordSecurity,
|
||||||
|
Management management, ValidationService validationService, PlayerCache playerCache) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.pluginHooks = pluginHooks;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
this.passwordSecurity = passwordSecurity;
|
||||||
|
this.management = management;
|
||||||
|
this.validationService = validationService;
|
||||||
|
this.playerCache = playerCache;
|
||||||
|
NewAPI.singleton = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the API object for AuthMe.
|
* Get the API object for AuthMe.
|
||||||
*
|
*
|
||||||
* @return The API object, or null if the AuthMe plugin instance could not be retrieved
|
* @return The API object, or null if the AuthMe plugin is not enabled or not fully initialized yet
|
||||||
* from the server environment
|
|
||||||
*/
|
*/
|
||||||
public static NewAPI getInstance() {
|
public static NewAPI getInstance() {
|
||||||
if (singleton != null) {
|
if (singleton != null) {
|
||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
|
// NewAPI is initialized in AuthMe#onEnable -> if singleton is null,
|
||||||
if (p == null || !(p instanceof AuthMe)) {
|
// it means AuthMe isn't initialized (yet)
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
AuthMe authme = (AuthMe) p;
|
|
||||||
singleton = new NewAPI(authme);
|
|
||||||
return singleton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,7 +88,7 @@ public class NewAPI {
|
|||||||
* @return true if the player is authenticated
|
* @return true if the player is authenticated
|
||||||
*/
|
*/
|
||||||
public boolean isAuthenticated(Player player) {
|
public boolean isAuthenticated(Player player) {
|
||||||
return PlayerCache.getInstance().isAuthenticated(player.getName());
|
return playerCache.isAuthenticated(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +98,7 @@ public class NewAPI {
|
|||||||
* @return true if the player is an npc
|
* @return true if the player is an npc
|
||||||
*/
|
*/
|
||||||
public boolean isNPC(Player player) {
|
public boolean isNPC(Player player) {
|
||||||
return plugin.getPluginHooks().isNpc(player);
|
return pluginHooks.isNpc(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,17 +110,17 @@ public class NewAPI {
|
|||||||
* @see fr.xephi.authme.settings.properties.RestrictionSettings#UNRESTRICTED_NAMES
|
* @see fr.xephi.authme.settings.properties.RestrictionSettings#UNRESTRICTED_NAMES
|
||||||
*/
|
*/
|
||||||
public boolean isUnrestricted(Player player) {
|
public boolean isUnrestricted(Player player) {
|
||||||
return Utils.isUnrestricted(player);
|
return validationService.isUnrestricted(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the last location of a player.
|
* Get the last location of an online player.
|
||||||
*
|
*
|
||||||
* @param player The player to process
|
* @param player The player to process
|
||||||
* @return Location The location of the player
|
* @return Location The location of the player
|
||||||
*/
|
*/
|
||||||
public Location getLastLocation(Player player) {
|
public Location getLastLocation(Player player) {
|
||||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName());
|
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
|
return new Location(Bukkit.getWorld(auth.getWorld()), auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ());
|
||||||
}
|
}
|
||||||
@ -125,7 +135,7 @@ public class NewAPI {
|
|||||||
*/
|
*/
|
||||||
public boolean isRegistered(String playerName) {
|
public boolean isRegistered(String playerName) {
|
||||||
String player = playerName.toLowerCase();
|
String player = playerName.toLowerCase();
|
||||||
return plugin.getDataSource().isAuthAvailable(player);
|
return dataSource.isAuthAvailable(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +146,7 @@ public class NewAPI {
|
|||||||
* @return true if the password is correct, false otherwise
|
* @return true if the password is correct, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean checkPassword(String playerName, String passwordToCheck) {
|
public boolean checkPassword(String playerName, String passwordToCheck) {
|
||||||
return isRegistered(playerName) && plugin.getPasswordSecurity().comparePassword(passwordToCheck, playerName);
|
return passwordSecurity.comparePassword(passwordToCheck, playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,7 +159,7 @@ public class NewAPI {
|
|||||||
*/
|
*/
|
||||||
public boolean registerPlayer(String playerName, String password) {
|
public boolean registerPlayer(String playerName, String password) {
|
||||||
String name = playerName.toLowerCase();
|
String name = playerName.toLowerCase();
|
||||||
HashedPassword result = plugin.getPasswordSecurity().computeHash(password, name);
|
HashedPassword result = passwordSecurity.computeHash(password, name);
|
||||||
if (isRegistered(name)) {
|
if (isRegistered(name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -158,7 +168,7 @@ public class NewAPI {
|
|||||||
.password(result)
|
.password(result)
|
||||||
.realName(playerName)
|
.realName(playerName)
|
||||||
.build();
|
.build();
|
||||||
return plugin.getDataSource().saveAuth(auth);
|
return dataSource.saveAuth(auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +177,7 @@ public class NewAPI {
|
|||||||
* @param player The player to log in
|
* @param player The player to log in
|
||||||
*/
|
*/
|
||||||
public void forceLogin(Player player) {
|
public void forceLogin(Player player) {
|
||||||
plugin.getManagement().performLogin(player, "dontneed", true);
|
management.performLogin(player, "dontneed", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,7 +186,7 @@ public class NewAPI {
|
|||||||
* @param player The player to log out
|
* @param player The player to log out
|
||||||
*/
|
*/
|
||||||
public void forceLogout(Player player) {
|
public void forceLogout(Player player) {
|
||||||
plugin.getManagement().performLogout(player);
|
management.performLogout(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,7 +197,7 @@ public class NewAPI {
|
|||||||
* @param autoLogin Should the player be authenticated automatically after the registration?
|
* @param autoLogin Should the player be authenticated automatically after the registration?
|
||||||
*/
|
*/
|
||||||
public void forceRegister(Player player, String password, boolean autoLogin) {
|
public void forceRegister(Player player, String password, boolean autoLogin) {
|
||||||
plugin.getManagement().performRegister(player, password, null, autoLogin);
|
management.performRegister(player, password, null, autoLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,6 +216,6 @@ public class NewAPI {
|
|||||||
* @param player The player to unregister
|
* @param player The player to unregister
|
||||||
*/
|
*/
|
||||||
public void forceUnregister(Player player) {
|
public void forceUnregister(Player player) {
|
||||||
plugin.getManagement().performUnregister(player, "", true);
|
management.performUnregisterByAdmin(null, player.getName(), player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.cache;
|
|||||||
|
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.security.RandomString;
|
import fr.xephi.authme.security.RandomString;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -21,10 +21,10 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
private int captchaLength;
|
private int captchaLength;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CaptchaManager(NewSetting settings) {
|
CaptchaManager(Settings settings) {
|
||||||
this.playerCounts = new ConcurrentHashMap<>();
|
this.playerCounts = new ConcurrentHashMap<>();
|
||||||
this.captchaCodes = new ConcurrentHashMap<>();
|
this.captchaCodes = new ConcurrentHashMap<>();
|
||||||
loadSettings(settings);
|
reload(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +123,7 @@ public class CaptchaManager implements SettingsDependent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSettings(NewSetting settings) {
|
public void reload(Settings settings) {
|
||||||
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
||||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
||||||
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
this.captchaLength = settings.getProperty(SecuritySettings.CAPTCHA_LENGTH);
|
||||||
|
|||||||
96
src/main/java/fr/xephi/authme/cache/SessionManager.java
vendored
Normal file
96
src/main/java/fr/xephi/authme/cache/SessionManager.java
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package fr.xephi.authme.cache;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.initialization.HasCleanup;
|
||||||
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages sessions, allowing players to be automatically logged in if they join again
|
||||||
|
* within a configurable amount of time.
|
||||||
|
*/
|
||||||
|
public class SessionManager implements SettingsDependent, HasCleanup {
|
||||||
|
|
||||||
|
private static final int MINUTE_IN_MILLIS = 60_000;
|
||||||
|
// Player -> expiration of session in milliseconds
|
||||||
|
private final Map<String, Long> sessions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private boolean enabled;
|
||||||
|
private int timeoutInMinutes;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SessionManager(Settings settings) {
|
||||||
|
reload(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a session is available for the given player.
|
||||||
|
*
|
||||||
|
* @param name The name to check.
|
||||||
|
* @return True if a session is found.
|
||||||
|
*/
|
||||||
|
public boolean hasSession(String name) {
|
||||||
|
if (enabled) {
|
||||||
|
Long timeout = sessions.get(name.toLowerCase());
|
||||||
|
if (timeout != null) {
|
||||||
|
return System.currentTimeMillis() <= timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a player session to the cache.
|
||||||
|
*
|
||||||
|
* @param name The name of the player.
|
||||||
|
*/
|
||||||
|
public void addSession(String name) {
|
||||||
|
if (enabled) {
|
||||||
|
long timeout = System.currentTimeMillis() + timeoutInMinutes * MINUTE_IN_MILLIS;
|
||||||
|
sessions.put(name.toLowerCase(), timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a player's session from the cache.
|
||||||
|
*
|
||||||
|
* @param name The name of the player.
|
||||||
|
*/
|
||||||
|
public void removeSession(String name) {
|
||||||
|
this.sessions.remove(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload(Settings settings) {
|
||||||
|
timeoutInMinutes = settings.getProperty(PluginSettings.SESSIONS_TIMEOUT);
|
||||||
|
boolean oldEnabled = enabled;
|
||||||
|
enabled = timeoutInMinutes > 0 && settings.getProperty(PluginSettings.SESSIONS_ENABLED);
|
||||||
|
|
||||||
|
// With this reload, the sessions feature has just been disabled, so clear all stored sessions
|
||||||
|
if (oldEnabled && !enabled) {
|
||||||
|
sessions.clear();
|
||||||
|
ConsoleLogger.fine("Sessions disabled: cleared all sessions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performCleanup() {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long currentTime = System.currentTimeMillis();
|
||||||
|
Iterator<Map.Entry<String, Long>> iterator = sessions.entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<String, Long> entry = iterator.next();
|
||||||
|
if (entry.getValue() < currentTime) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ package fr.xephi.authme.cache;
|
|||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.Utils;
|
||||||
@ -30,11 +30,11 @@ public class TempbanManager implements SettingsDependent {
|
|||||||
private int length;
|
private int length;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
TempbanManager(BukkitService bukkitService, Messages messages, NewSetting settings) {
|
TempbanManager(BukkitService bukkitService, Messages messages, Settings settings) {
|
||||||
this.ipLoginFailureCounts = new ConcurrentHashMap<>();
|
this.ipLoginFailureCounts = new ConcurrentHashMap<>();
|
||||||
this.bukkitService = bukkitService;
|
this.bukkitService = bukkitService;
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
loadSettings(settings);
|
reload(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,7 +108,7 @@ public class TempbanManager implements SettingsDependent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSettings(NewSetting settings) {
|
public void reload(Settings settings) {
|
||||||
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
|
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
|
||||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
|
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
|
||||||
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
|
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
|
||||||
|
|||||||
@ -85,6 +85,13 @@ public class PlayerAuth {
|
|||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setQuitLocation(Location location) {
|
||||||
|
x = location.getBlockX();
|
||||||
|
y = location.getBlockY();
|
||||||
|
z = location.getBlockZ();
|
||||||
|
world = location.getWorld().getName();
|
||||||
|
}
|
||||||
|
|
||||||
public double getQuitLocX() {
|
public double getQuitLocX() {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
package fr.xephi.authme.cache.auth;
|
package fr.xephi.authme.cache.auth;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Used to manage player's Authenticated status
|
||||||
*/
|
*/
|
||||||
public class PlayerCache {
|
public class PlayerCache {
|
||||||
|
|
||||||
@ -34,7 +34,6 @@ public class PlayerCache {
|
|||||||
* @param auth PlayerAuth
|
* @param auth PlayerAuth
|
||||||
*/
|
*/
|
||||||
public void addPlayer(PlayerAuth auth) {
|
public void addPlayer(PlayerAuth auth) {
|
||||||
ConsoleLogger.debug("ADDED PLAYER TO CACHE " + auth.getNickname());
|
|
||||||
cache.put(auth.getNickname().toLowerCase(), auth);
|
cache.put(auth.getNickname().toLowerCase(), auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +43,6 @@ public class PlayerCache {
|
|||||||
* @param auth PlayerAuth
|
* @param auth PlayerAuth
|
||||||
*/
|
*/
|
||||||
public void updatePlayer(PlayerAuth auth) {
|
public void updatePlayer(PlayerAuth auth) {
|
||||||
ConsoleLogger.debug("UPDATE PLAYER " + auth.getNickname());
|
|
||||||
cache.put(auth.getNickname(), auth);
|
cache.put(auth.getNickname(), auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,16 +52,15 @@ public class PlayerCache {
|
|||||||
* @param user String
|
* @param user String
|
||||||
*/
|
*/
|
||||||
public void removePlayer(String user) {
|
public void removePlayer(String user) {
|
||||||
ConsoleLogger.debug("REMOVE PLAYER " + user);
|
|
||||||
cache.remove(user.toLowerCase());
|
cache.remove(user.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method isAuthenticated.
|
* get player's authenticated status.
|
||||||
*
|
*
|
||||||
* @param user String
|
* @param user player's name
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return true if player is logged in, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isAuthenticated(String user) {
|
public boolean isAuthenticated(String user) {
|
||||||
return cache.containsKey(user.toLowerCase());
|
return cache.containsKey(user.toLowerCase());
|
||||||
|
|||||||
@ -1,131 +0,0 @@
|
|||||||
package fr.xephi.authme.cache.backup;
|
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
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.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public class JsonCache {
|
|
||||||
|
|
||||||
private final Gson gson;
|
|
||||||
private final File cacheDir;
|
|
||||||
|
|
||||||
public JsonCache() {
|
|
||||||
cacheDir = new File(AuthMe.getInstance().getDataFolder(), "cache");
|
|
||||||
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
|
|
||||||
ConsoleLogger.showError("Failed to create cache directory.");
|
|
||||||
}
|
|
||||||
gson = new GsonBuilder()
|
|
||||||
.registerTypeAdapter(PlayerData.class, new PlayerDataSerializer())
|
|
||||||
.registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer())
|
|
||||||
.setPrettyPrinting()
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData readCache(Player player) {
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
File file = new File(cacheDir, name + File.separator + "cache.json");
|
|
||||||
if (!file.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String str = Files.toString(file, Charsets.UTF_8);
|
|
||||||
return gson.fromJson(str, PlayerData.class);
|
|
||||||
} catch (IOException e) {
|
|
||||||
ConsoleLogger.writeStackTrace(e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeCache(Player player) {
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
File file = new File(cacheDir, name);
|
|
||||||
if (file.exists()) {
|
|
||||||
purgeDirectory(file);
|
|
||||||
if (!file.delete()) {
|
|
||||||
ConsoleLogger.showError("Failed to remove" + player.getName() + "cache.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean doesCacheExist(Player player) {
|
|
||||||
String name = player.getName().toLowerCase();
|
|
||||||
File file = new File(cacheDir, name + File.separator + "cache.json");
|
|
||||||
return file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PlayerDataDeserializer implements JsonDeserializer<PlayerData> {
|
|
||||||
@Override
|
|
||||||
public PlayerData deserialize(JsonElement jsonElement, Type type,
|
|
||||||
JsonDeserializationContext context) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
if (jsonObject == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String group = null;
|
|
||||||
boolean operator = false;
|
|
||||||
boolean fly = false;
|
|
||||||
|
|
||||||
JsonElement e;
|
|
||||||
if ((e = jsonObject.get("group")) != null) {
|
|
||||||
group = e.getAsString();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("operator")) != null) {
|
|
||||||
operator = e.getAsBoolean();
|
|
||||||
}
|
|
||||||
if ((e = jsonObject.get("fly")) != null) {
|
|
||||||
fly = e.getAsBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PlayerData(group, operator, fly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PlayerDataSerializer implements JsonSerializer<PlayerData> {
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(PlayerData playerData, Type type,
|
|
||||||
JsonSerializationContext context) {
|
|
||||||
JsonObject jsonObject = new JsonObject();
|
|
||||||
jsonObject.addProperty("group", playerData.getGroup());
|
|
||||||
jsonObject.addProperty("operator", playerData.getOperator());
|
|
||||||
jsonObject.addProperty("fly", playerData.isFlyEnabled());
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a given directory and all its content.
|
|
||||||
*
|
|
||||||
* @param directory The directory to remove
|
|
||||||
*/
|
|
||||||
private static void purgeDirectory(File directory) {
|
|
||||||
if (!directory.isDirectory()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
File[] files = directory.listFiles();
|
|
||||||
if (files == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (File target : files) {
|
|
||||||
if (target.isDirectory()) {
|
|
||||||
purgeDirectory(target);
|
|
||||||
}
|
|
||||||
target.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package fr.xephi.authme.cache.backup;
|
|
||||||
|
|
||||||
public class PlayerData {
|
|
||||||
|
|
||||||
private final String group;
|
|
||||||
private final boolean operator;
|
|
||||||
private final boolean flyEnabled;
|
|
||||||
|
|
||||||
public PlayerData(String group, boolean operator, boolean flyEnabled) {
|
|
||||||
this.group = group;
|
|
||||||
this.operator = operator;
|
|
||||||
this.flyEnabled = flyEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getGroup() {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getOperator() {
|
|
||||||
return operator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFlyEnabled() {
|
|
||||||
return flyEnabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
214
src/main/java/fr/xephi/authme/cache/backup/PlayerDataStorage.java
vendored
Normal file
214
src/main/java/fr/xephi/authme/cache/backup/PlayerDataStorage.java
vendored
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package fr.xephi.authme.cache.backup;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
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.cache.limbo.PlayerData;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
|
import fr.xephi.authme.util.BukkitService;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to store player's data (OP, flying, speed, position) to disk.
|
||||||
|
*/
|
||||||
|
public class PlayerDataStorage {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final File cacheDir;
|
||||||
|
private PermissionsManager permissionsManager;
|
||||||
|
private SpawnLoader spawnLoader;
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PlayerDataStorage(@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(PlayerData.class, new PlayerDataSerializer())
|
||||||
|
.registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer())
|
||||||
|
.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 PlayerData readData(Player player) {
|
||||||
|
String id = Utils.getUUIDorName(player);
|
||||||
|
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String str = Files.toString(file, Charsets.UTF_8);
|
||||||
|
return gson.fromJson(str, PlayerData.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 = Utils.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();
|
||||||
|
PlayerData playerData = new PlayerData(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(playerData), file, Charsets.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 = Utils.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 = Utils.getUUIDorName(player);
|
||||||
|
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PlayerDataDeserializer implements JsonDeserializer<PlayerData> {
|
||||||
|
@Override
|
||||||
|
public PlayerData 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 = 0.2f;
|
||||||
|
float flySpeed = 0.2f;
|
||||||
|
|
||||||
|
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 PlayerData(loc, operator, group, canFly, walkSpeed, flySpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PlayerDataSerializer implements JsonSerializer<PlayerData> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(PlayerData playerData, Type type,
|
||||||
|
JsonSerializationContext context) {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("group", playerData.getGroup());
|
||||||
|
|
||||||
|
Location loc = playerData.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", playerData.isOperator());
|
||||||
|
obj.addProperty("can-fly", playerData.isCanFly());
|
||||||
|
obj.addProperty("walk-speed", playerData.getWalkSpeed());
|
||||||
|
obj.addProperty("fly-speed", playerData.getFlySpeed());
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,111 +1,164 @@
|
|||||||
package fr.xephi.authme.cache.limbo;
|
package fr.xephi.authme.cache.limbo;
|
||||||
|
|
||||||
import fr.xephi.authme.cache.backup.JsonCache;
|
import fr.xephi.authme.cache.backup.PlayerDataStorage;
|
||||||
import fr.xephi.authme.cache.backup.PlayerData;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages all {@link LimboPlayer} instances.
|
* Manages all {@link PlayerData} instances.
|
||||||
*/
|
*/
|
||||||
public class LimboCache {
|
public class LimboCache {
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
private final Map<String, PlayerData> cache = new ConcurrentHashMap<>();
|
||||||
private final JsonCache jsonCache = new JsonCache();
|
|
||||||
|
|
||||||
@Inject
|
private PlayerDataStorage playerDataStorage;
|
||||||
|
private Settings settings;
|
||||||
private PermissionsManager permissionsManager;
|
private PermissionsManager permissionsManager;
|
||||||
@Inject
|
|
||||||
private SpawnLoader spawnLoader;
|
private SpawnLoader spawnLoader;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader) {
|
LimboCache(Settings settings, PermissionsManager permissionsManager,
|
||||||
|
SpawnLoader spawnLoader, PlayerDataStorage playerDataStorage) {
|
||||||
|
this.settings = settings;
|
||||||
this.permissionsManager = permissionsManager;
|
this.permissionsManager = permissionsManager;
|
||||||
this.spawnLoader = spawnLoader;
|
this.spawnLoader = spawnLoader;
|
||||||
|
this.playerDataStorage = playerDataStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a limbo player.
|
* Load player data if exist, otherwise current player's data will be stored.
|
||||||
*
|
*
|
||||||
* @param player Player instance to add.
|
* @param player Player instance to add.
|
||||||
*/
|
*/
|
||||||
public void addLimboPlayer(Player player) {
|
public void addPlayerData(Player player) {
|
||||||
String name = player.getName().toLowerCase();
|
String name = player.getName().toLowerCase();
|
||||||
Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation();
|
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||||
boolean operator = player.isOp();
|
boolean operator = player.isOp();
|
||||||
boolean flyEnabled = player.getAllowFlight();
|
boolean flyEnabled = player.getAllowFlight();
|
||||||
|
float walkSpeed = player.getWalkSpeed();
|
||||||
|
float flySpeed = player.getFlySpeed();
|
||||||
String playerGroup = "";
|
String playerGroup = "";
|
||||||
if (permissionsManager.hasGroupSupport()) {
|
if (permissionsManager.hasGroupSupport()) {
|
||||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
playerGroup = permissionsManager.getPrimaryGroup(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonCache.doesCacheExist(player)) {
|
if (playerDataStorage.hasData(player)) {
|
||||||
PlayerData cache = jsonCache.readCache(player);
|
PlayerData cache = playerDataStorage.readData(player);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
|
location = cache.getLocation();
|
||||||
playerGroup = cache.getGroup();
|
playerGroup = cache.getGroup();
|
||||||
operator = cache.getOperator();
|
operator = cache.isOperator();
|
||||||
flyEnabled = cache.isFlyEnabled();
|
flyEnabled = cache.isCanFly();
|
||||||
|
walkSpeed = cache.getWalkSpeed();
|
||||||
|
flySpeed = cache.getFlySpeed();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
playerDataStorage.saveData(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache.put(name, new PlayerData(location, operator, playerGroup, flyEnabled, walkSpeed, flySpeed));
|
||||||
cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method deleteLimboPlayer.
|
* Restore player's data to player if exist.
|
||||||
*
|
*
|
||||||
* @param name String
|
* @param player Player instance to restore
|
||||||
*/
|
*/
|
||||||
public void deleteLimboPlayer(String name) {
|
public void restoreData(Player player) {
|
||||||
checkNotNull(name);
|
String lowerName = player.getName().toLowerCase();
|
||||||
name = name.toLowerCase();
|
if (cache.containsKey(lowerName)) {
|
||||||
LimboPlayer cachedPlayer = cache.remove(name);
|
PlayerData 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 == 0f) {
|
||||||
|
walkSpeed = 0.2f;
|
||||||
|
}
|
||||||
|
if(flySpeed == 0f) {
|
||||||
|
flySpeed = 0.2f;
|
||||||
|
}
|
||||||
|
player.setWalkSpeed(walkSpeed);
|
||||||
|
player.setFlySpeed(flySpeed);
|
||||||
|
restoreGroup(player, data.getGroup());
|
||||||
|
data.clearTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove PlayerData from cache and disk.
|
||||||
|
*
|
||||||
|
* @param player Player player to remove.
|
||||||
|
*/
|
||||||
|
public void deletePlayerData(Player player) {
|
||||||
|
removeFromCache(player);
|
||||||
|
playerDataStorage.removeData(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove PlayerData from cache.
|
||||||
|
*
|
||||||
|
* @param player player to remove.
|
||||||
|
*/
|
||||||
|
public void removeFromCache(Player player) {
|
||||||
|
String name = player.getName().toLowerCase();
|
||||||
|
PlayerData cachedPlayer = cache.remove(name);
|
||||||
if (cachedPlayer != null) {
|
if (cachedPlayer != null) {
|
||||||
cachedPlayer.clearTasks();
|
cachedPlayer.clearTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method getLimboPlayer.
|
* Method getPlayerData.
|
||||||
*
|
*
|
||||||
* @param name String
|
* @param name String
|
||||||
*
|
*
|
||||||
* @return LimboPlayer
|
* @return PlayerData
|
||||||
*/
|
*/
|
||||||
public LimboPlayer getLimboPlayer(String name) {
|
public PlayerData getPlayerData(String name) {
|
||||||
checkNotNull(name);
|
checkNotNull(name);
|
||||||
return cache.get(name.toLowerCase());
|
return cache.get(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method hasLimboPlayer.
|
* Method hasPlayerData.
|
||||||
*
|
*
|
||||||
* @param name String
|
* @param name String
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean hasLimboPlayer(String name) {
|
public boolean hasPlayerData(String name) {
|
||||||
checkNotNull(name);
|
checkNotNull(name);
|
||||||
return cache.containsKey(name.toLowerCase());
|
return cache.containsKey(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method updateLimboPlayer.
|
* Method updatePlayerData.
|
||||||
*
|
*
|
||||||
* @param player Player
|
* @param player Player
|
||||||
*/
|
*/
|
||||||
public void updateLimboPlayer(Player player) {
|
public void updatePlayerData(Player player) {
|
||||||
checkNotNull(player);
|
checkNotNull(player);
|
||||||
deleteLimboPlayer(player.getName().toLowerCase());
|
removeFromCache(player);
|
||||||
addLimboPlayer(player);
|
addPlayerData(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void restoreGroup(Player player, String group) {
|
||||||
|
if (!StringUtils.isEmpty(group) && permissionsManager.hasGroupSupport()
|
||||||
|
&& settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
||||||
|
permissionsManager.setGroup(player, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,32 +7,25 @@ import org.bukkit.scheduler.BukkitTask;
|
|||||||
* Represents a player which is not logged in and keeps track of certain states (like OP status, flying)
|
* Represents a player which is not logged in and keeps track of certain states (like OP status, flying)
|
||||||
* which may be revoked from the player until he has logged in or registered.
|
* which may be revoked from the player until he has logged in or registered.
|
||||||
*/
|
*/
|
||||||
public class LimboPlayer {
|
public class PlayerData {
|
||||||
|
|
||||||
private final String name;
|
private final boolean canFly;
|
||||||
private final boolean fly;
|
private final boolean operator;
|
||||||
private Location loc = null;
|
private final String group;
|
||||||
|
private final Location loc;
|
||||||
|
private final float walkSpeed;
|
||||||
|
private final float flySpeed;
|
||||||
private BukkitTask timeoutTask = null;
|
private BukkitTask timeoutTask = null;
|
||||||
private BukkitTask messageTask = null;
|
private BukkitTask messageTask = null;
|
||||||
private boolean operator = false;
|
|
||||||
private String group;
|
|
||||||
|
|
||||||
public LimboPlayer(String name, Location loc, boolean operator,
|
public PlayerData(Location loc, boolean operator,
|
||||||
String group, boolean fly) {
|
String group, boolean fly, float walkSpeed, float flySpeed) {
|
||||||
this.name = name;
|
|
||||||
this.loc = loc;
|
this.loc = loc;
|
||||||
this.operator = operator;
|
this.operator = operator;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.fly = fly;
|
this.canFly = fly;
|
||||||
}
|
this.walkSpeed = walkSpeed;
|
||||||
|
this.flySpeed = flySpeed;
|
||||||
/**
|
|
||||||
* Return the name of the player.
|
|
||||||
*
|
|
||||||
* @return The player's name
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +33,7 @@ public class LimboPlayer {
|
|||||||
*
|
*
|
||||||
* @return The player's location
|
* @return The player's location
|
||||||
*/
|
*/
|
||||||
public Location getLoc() {
|
public Location getLocation() {
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,8 +55,16 @@ public class LimboPlayer {
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFly() {
|
public boolean isCanFly() {
|
||||||
return fly;
|
return canFly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWalkSpeed() {
|
||||||
|
return walkSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFlySpeed() {
|
||||||
|
return flySpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package fr.xephi.authme.command;
|
package fr.xephi.authme.command;
|
||||||
|
|
||||||
|
import ch.jalu.injector.Injector;
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -37,12 +37,12 @@ public class CommandHandler {
|
|||||||
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
|
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CommandHandler(AuthMeServiceInitializer initializer, CommandMapper commandMapper,
|
public CommandHandler(Injector injector, CommandMapper commandMapper,
|
||||||
PermissionsManager permissionsManager, HelpProvider helpProvider) {
|
PermissionsManager permissionsManager, HelpProvider helpProvider) {
|
||||||
this.commandMapper = commandMapper;
|
this.commandMapper = commandMapper;
|
||||||
this.permissionsManager = permissionsManager;
|
this.permissionsManager = permissionsManager;
|
||||||
this.helpProvider = helpProvider;
|
this.helpProvider = helpProvider;
|
||||||
initializeCommands(initializer, commandMapper.getCommandClasses());
|
initializeCommands(injector, commandMapper.getCommandClasses());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,12 +90,13 @@ public class CommandHandler {
|
|||||||
/**
|
/**
|
||||||
* Initialize all required ExecutableCommand objects.
|
* Initialize all required ExecutableCommand objects.
|
||||||
*
|
*
|
||||||
|
* @param injector the injector
|
||||||
* @param commandClasses the classes to instantiate
|
* @param commandClasses the classes to instantiate
|
||||||
*/
|
*/
|
||||||
private void initializeCommands(AuthMeServiceInitializer initializer,
|
private void initializeCommands(Injector injector,
|
||||||
Set<Class<? extends ExecutableCommand>> commandClasses) {
|
Set<Class<? extends ExecutableCommand>> commandClasses) {
|
||||||
for (Class<? extends ExecutableCommand> clazz : commandClasses) {
|
for (Class<? extends ExecutableCommand> clazz : commandClasses) {
|
||||||
commands.put(clazz, initializer.newInstance(clazz));
|
commands.put(clazz, injector.newInstance(clazz));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.command;
|
|||||||
|
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.domain.Property;
|
import fr.xephi.authme.settings.domain.Property;
|
||||||
import fr.xephi.authme.util.ValidationService;
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -18,7 +18,7 @@ public class CommandService {
|
|||||||
@Inject
|
@Inject
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
@Inject
|
@Inject
|
||||||
private NewSetting settings;
|
private Settings settings;
|
||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
|
|
||||||
@ -53,6 +53,16 @@ public class CommandService {
|
|||||||
return messages.retrieve(key);
|
return messages.retrieve(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a message as a single String by its message key.
|
||||||
|
*
|
||||||
|
* @param key The message to retrieve
|
||||||
|
* @return The message
|
||||||
|
*/
|
||||||
|
public String retrieveSingle(MessageKey key) {
|
||||||
|
return messages.retrieveSingle(key);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the given property's value.
|
* Retrieve the given property's value.
|
||||||
*
|
*
|
||||||
@ -69,7 +79,7 @@ public class CommandService {
|
|||||||
*
|
*
|
||||||
* @return The settings manager
|
* @return The settings manager
|
||||||
*/
|
*/
|
||||||
public NewSetting getSettings() {
|
public Settings getSettings() {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
|
|||||||
|
|
||||||
if (dataSource.updatePassword(auth)) {
|
if (dataSource.updatePassword(auth)) {
|
||||||
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
|
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
|
||||||
ConsoleLogger.info(playerNameLowerCase + "'s password changed");
|
ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase);
|
||||||
} else {
|
} else {
|
||||||
commandService.send(sender, MessageKey.ERROR);
|
commandService.send(sender, MessageKey.ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
|
import ch.jalu.injector.Injector;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.converter.Converter;
|
import fr.xephi.authme.converter.Converter;
|
||||||
@ -10,7 +12,6 @@ import fr.xephi.authme.converter.RoyalAuthConverter;
|
|||||||
import fr.xephi.authme.converter.SqliteToSql;
|
import fr.xephi.authme.converter.SqliteToSql;
|
||||||
import fr.xephi.authme.converter.vAuthConverter;
|
import fr.xephi.authme.converter.vAuthConverter;
|
||||||
import fr.xephi.authme.converter.xAuthConverter;
|
import fr.xephi.authme.converter.xAuthConverter;
|
||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -30,7 +31,7 @@ public class ConverterCommand implements ExecutableCommand {
|
|||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AuthMeServiceInitializer initializer;
|
private Injector injector;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||||
@ -45,13 +46,17 @@ public class ConverterCommand implements ExecutableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the proper converter instance
|
// Get the proper converter instance
|
||||||
final Converter converter = initializer.newInstance(jobType.getConverterClass());
|
final Converter converter = injector.newInstance(jobType.getConverterClass());
|
||||||
|
|
||||||
// Run the convert job
|
// Run the convert job
|
||||||
bukkitService.runTaskAsynchronously(new Runnable() {
|
bukkitService.runTaskAsynchronously(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
converter.execute(sender);
|
try {
|
||||||
|
converter.execute(sender);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ConsoleLogger.logException("Error during conversion:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.task.purge.PurgeService;
|
||||||
import fr.xephi.authme.task.PurgeTask;
|
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
@ -21,10 +18,7 @@ import java.util.Set;
|
|||||||
public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private PurgeService purgeService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthMe plugin;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
@ -32,18 +26,12 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||||
// Get the list of banned players
|
// Get the list of banned players
|
||||||
Set<String> namedBanned = new HashSet<>();
|
|
||||||
Set<OfflinePlayer> bannedPlayers = bukkitService.getBannedPlayers();
|
Set<OfflinePlayer> bannedPlayers = bukkitService.getBannedPlayers();
|
||||||
|
Set<String> namedBanned = new HashSet<>(bannedPlayers.size());
|
||||||
for (OfflinePlayer offlinePlayer : bannedPlayers) {
|
for (OfflinePlayer offlinePlayer : bannedPlayers) {
|
||||||
namedBanned.add(offlinePlayer.getName().toLowerCase());
|
namedBanned.add(offlinePlayer.getName().toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: note this should may run async because it may executes a SQL-Query
|
purgeService.purgePlayers(sender, namedBanned, bannedPlayers.toArray(new OfflinePlayer[bannedPlayers.size()]));
|
||||||
// Purge the banned players
|
|
||||||
dataSource.purgeBanned(namedBanned);
|
|
||||||
|
|
||||||
// Show a status message
|
|
||||||
sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
|
|
||||||
new PurgeTask(plugin, sender, namedBanned, bannedPlayers).runTaskTimer(plugin, 0, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.task.purge.PurgeService;
|
||||||
import fr.xephi.authme.task.PurgeTask;
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command for purging the data of players which have not been since for a given number
|
* Command for purging the data of players which have not been since for a given number
|
||||||
@ -21,10 +18,7 @@ public class PurgeCommand implements ExecutableCommand {
|
|||||||
private static final int MINIMUM_LAST_SEEN_DAYS = 30;
|
private static final int MINIMUM_LAST_SEEN_DAYS = 30;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private PurgeService purgeService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthMe plugin;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||||
@ -52,13 +46,7 @@ public class PurgeCommand implements ExecutableCommand {
|
|||||||
calendar.add(Calendar.DATE, -days);
|
calendar.add(Calendar.DATE, -days);
|
||||||
long until = calendar.getTimeInMillis();
|
long until = calendar.getTimeInMillis();
|
||||||
|
|
||||||
//todo: note this should may run async because it may executes a SQL-Query
|
// Run the purge
|
||||||
// Purge the data, get the purged values
|
purgeService.runPurge(sender, until);
|
||||||
Set<String> purged = dataSource.autoPurgeDatabase(until);
|
|
||||||
|
|
||||||
// Show a status message
|
|
||||||
sender.sendMessage(ChatColor.GOLD + "Deleted " + purged.size() + " user accounts");
|
|
||||||
sender.sendMessage(ChatColor.GOLD + "Purging user accounts...");
|
|
||||||
new PurgeTask(plugin, sender, purged).runTaskTimer(plugin, 0, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.authme;
|
|||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
@ -37,6 +38,9 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ValidationService validationService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LimboCache limboCache;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||||
// Get the player name and password
|
// Get the player name and password
|
||||||
@ -79,7 +83,8 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
|||||||
bukkitService.scheduleSyncDelayedTask(new Runnable() {
|
bukkitService.scheduleSyncDelayedTask(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
player.kickPlayer("An admin just registered you, please log in again");
|
limboCache.restoreData(player);
|
||||||
|
player.kickPlayer(commandService.retrieveSingle(MessageKey.KICK_FOR_ADMIN_REGISTER));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
|
import ch.jalu.injector.Injector;
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,10 +26,10 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
private AuthMe plugin;
|
private AuthMe plugin;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AuthMeServiceInitializer initializer;
|
private Injector injector;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private NewSetting settings;
|
private Settings settings;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
@ -44,7 +47,7 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
ConsoleLogger.info("Note: cannot change database type during /authme reload");
|
ConsoleLogger.info("Note: cannot change database type during /authme reload");
|
||||||
sender.sendMessage("Note: cannot change database type during /authme reload");
|
sender.sendMessage("Note: cannot change database type during /authme reload");
|
||||||
}
|
}
|
||||||
initializer.performReloadOnServices();
|
performReloadOnServices();
|
||||||
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
|
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
|
||||||
@ -52,4 +55,16 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
plugin.stopOrUnload();
|
plugin.stopOrUnload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void performReloadOnServices() {
|
||||||
|
Collection<Reloadable> reloadables = injector.retrieveAllOfType(Reloadable.class);
|
||||||
|
for (Reloadable reloadable : reloadables) {
|
||||||
|
reloadable.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<SettingsDependent> settingsDependents = injector.retrieveAllOfType(SettingsDependent.class);
|
||||||
|
for (SettingsDependent dependent : settingsDependents) {
|
||||||
|
dependent.reload(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,17 @@
|
|||||||
package fr.xephi.authme.command.executable.authme;
|
package fr.xephi.authme.command.executable.authme;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
|
||||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.permission.AuthGroupHandler;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.permission.AuthGroupType;
|
|
||||||
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.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.Utils;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.potion.PotionEffect;
|
|
||||||
import org.bukkit.potion.PotionEffectType;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin command to unregister a player.
|
* Admin command to unregister a player.
|
||||||
*/
|
*/
|
||||||
@ -35,74 +23,27 @@ public class UnregisterAdminCommand implements ExecutableCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private CommandService commandService;
|
private CommandService commandService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PlayerCache playerCache;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BukkitService bukkitService;
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private Management management;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthGroupHandler authGroupHandler;
|
|
||||||
|
|
||||||
|
UnregisterAdminCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||||
// Get the player name
|
|
||||||
String playerName = arguments.get(0);
|
String playerName = arguments.get(0);
|
||||||
String playerNameLowerCase = playerName.toLowerCase();
|
|
||||||
|
|
||||||
// Make sure the user is valid
|
// Make sure the user exists
|
||||||
if (!dataSource.isAuthAvailable(playerNameLowerCase)) {
|
if (!dataSource.isAuthAvailable(playerName)) {
|
||||||
commandService.send(sender, MessageKey.UNKNOWN_USER);
|
commandService.send(sender, MessageKey.UNKNOWN_USER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the player
|
// Get the player from the server and perform unregister
|
||||||
if (!dataSource.removeAuth(playerNameLowerCase)) {
|
Player target = bukkitService.getPlayerExact(playerName);
|
||||||
commandService.send(sender, MessageKey.ERROR);
|
management.performUnregisterByAdmin(sender, playerName, target);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unregister the player
|
|
||||||
Player target = bukkitService.getPlayerExact(playerNameLowerCase);
|
|
||||||
playerCache.removePlayer(playerNameLowerCase);
|
|
||||||
authGroupHandler.setGroup(target, AuthGroupType.UNREGISTERED);
|
|
||||||
if (target != null && target.isOnline()) {
|
|
||||||
if (commandService.getProperty(RegistrationSettings.FORCE)) {
|
|
||||||
applyUnregisteredEffectsAndTasks(target);
|
|
||||||
}
|
|
||||||
commandService.send(target, MessageKey.UNREGISTERED_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a status message
|
|
||||||
commandService.send(sender, MessageKey.UNREGISTERED_SUCCESS);
|
|
||||||
ConsoleLogger.info(sender.getName() + " unregistered " + playerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When registration is forced, applies the configured "unregistered effects" to the player as he
|
|
||||||
* would encounter when joining the server before logging on - reminder task to log in,
|
|
||||||
* timeout kick, blindness.
|
|
||||||
*
|
|
||||||
* @param target the player that was unregistered
|
|
||||||
*/
|
|
||||||
private void applyUnregisteredEffectsAndTasks(Player target) {
|
|
||||||
// TODO #765: Remove use of Utils method and behave according to settings
|
|
||||||
Utils.teleportToSpawn(target);
|
|
||||||
|
|
||||||
limboCache.addLimboPlayer(target);
|
|
||||||
limboPlayerTaskManager.registerTimeoutTask(target);
|
|
||||||
limboPlayerTaskManager.registerMessageTask(target.getName(), false);
|
|
||||||
|
|
||||||
final int timeout = commandService.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
|
|
||||||
if (commandService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
|
||||||
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,11 +31,13 @@ public class VersionCommand implements ExecutableCommand {
|
|||||||
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
|
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
|
||||||
sender.sendMessage(ChatColor.GOLD + "Developers:");
|
sender.sendMessage(ChatColor.GOLD + "Developers:");
|
||||||
Collection<? extends Player> onlinePlayers = bukkitService.getOnlinePlayers();
|
Collection<? extends Player> onlinePlayers = bukkitService.getOnlinePlayers();
|
||||||
printDeveloper(sender, "Xephi", "xephi59", "Lead Developer", onlinePlayers);
|
printDeveloper(sender, "Alexandre Vanhecke", "xephi59", "Original Author", onlinePlayers);
|
||||||
|
printDeveloper(sender, "Lucas J.", "ljacqu", "Main Developer", onlinePlayers);
|
||||||
|
printDeveloper(sender, "Gnat008", "gnat008", "Developer", onlinePlayers);
|
||||||
printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers);
|
printDeveloper(sender, "DNx5", "DNx5", "Developer", onlinePlayers);
|
||||||
printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers);
|
printDeveloper(sender, "games647", "games647", "Developer", onlinePlayers);
|
||||||
printDeveloper(sender, "Tim Visee", "timvisee", "Developer", onlinePlayers);
|
printDeveloper(sender, "Tim Visee", "timvisee", "Developer", onlinePlayers);
|
||||||
printDeveloper(sender, "Sgdc3", "sgdc3", "Project manager, Contributor", onlinePlayers);
|
printDeveloper(sender, "Gabriele C.", "sgdc3", "Project manager, Contributor", onlinePlayers);
|
||||||
sender.sendMessage(ChatColor.GOLD + "Website: " + ChatColor.WHITE +
|
sender.sendMessage(ChatColor.GOLD + "Website: " + ChatColor.WHITE +
|
||||||
"http://dev.bukkit.org/bukkit-plugins/authme-reloaded/");
|
"http://dev.bukkit.org/bukkit-plugins/authme-reloaded/");
|
||||||
sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0"
|
sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0"
|
||||||
|
|||||||
@ -47,7 +47,6 @@ public class ChangePasswordCommand extends PlayerCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO ljacqu 20160117: Call async task via Management
|
|
||||||
management.performPasswordChange(player, oldPassword, newPassword);
|
management.performPasswordChange(player, oldPassword, newPassword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,17 @@
|
|||||||
package fr.xephi.authme.command.executable.email;
|
package fr.xephi.authme.command.executable.email;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.mail.SendMailSSL;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.RandomString;
|
import fr.xephi.authme.security.RandomString;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -33,53 +32,39 @@ public class RecoverEmailCommand extends PlayerCommand {
|
|||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
// TODO #655: Remove injected AuthMe instance once Authme#mail is encapsulated
|
private SendMailSSL sendMailSsl;
|
||||||
private AuthMe plugin;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
final String playerMail = arguments.get(0);
|
final String playerMail = arguments.get(0);
|
||||||
final String playerName = player.getName();
|
final String playerName = player.getName();
|
||||||
|
|
||||||
if (plugin.mail == null) {
|
if (!sendMailSsl.hasAllInformation()) {
|
||||||
ConsoleLogger.showError("Mail API is not set");
|
ConsoleLogger.warning("Mail API is not set");
|
||||||
commandService.send(player, MessageKey.ERROR);
|
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dataSource.isAuthAvailable(playerName)) {
|
if (playerCache.isAuthenticated(playerName)) {
|
||||||
if (PlayerCache.getInstance().isAuthenticated(playerName)) {
|
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
|
||||||
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
|
|
||||||
HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
|
|
||||||
PlayerAuth auth;
|
|
||||||
if (playerCache.isAuthenticated(playerName)) {
|
|
||||||
auth = playerCache.getAuth(playerName);
|
|
||||||
} else if (dataSource.isAuthAvailable(playerName)) {
|
|
||||||
auth = dataSource.getAuth(playerName);
|
|
||||||
} else {
|
|
||||||
commandService.send(player, MessageKey.UNKNOWN_USER);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(commandService.getProperty(EmailSettings.MAIL_ACCOUNT))) {
|
|
||||||
ConsoleLogger.showError("No mail account set in settings");
|
|
||||||
commandService.send(player, MessageKey.ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(playerMail)
|
|
||||||
|| "your@email.com".equalsIgnoreCase(auth.getEmail())) {
|
|
||||||
commandService.send(player, MessageKey.INVALID_EMAIL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auth.setPassword(hashNew);
|
|
||||||
dataSource.updatePassword(auth);
|
|
||||||
plugin.mail.main(auth, thePass);
|
|
||||||
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
|
||||||
} else {
|
|
||||||
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerAuth auth = dataSource.getAuth(playerName);
|
||||||
|
if (auth == null) {
|
||||||
|
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(auth.getEmail())) {
|
||||||
|
commandService.send(player, MessageKey.INVALID_EMAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
|
||||||
|
HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
|
||||||
|
auth.setPassword(hashNew);
|
||||||
|
dataSource.updatePassword(auth);
|
||||||
|
sendMailSsl.sendPasswordMail(auth, thePass);
|
||||||
|
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.register;
|
|||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.PlayerCommand;
|
import fr.xephi.authme.command.PlayerCommand;
|
||||||
|
import fr.xephi.authme.mail.SendMailSSL;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.security.HashAlgorithm;
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
@ -27,6 +28,9 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private CommandService commandService;
|
private CommandService commandService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SendMailSSL sendMailSsl;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
if (commandService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
|
||||||
@ -63,11 +67,10 @@ public class RegisterCommand extends PlayerCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleEmailRegistration(Player player, List<String> arguments) {
|
private void handleEmailRegistration(Player player, List<String> arguments) {
|
||||||
if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
|
if (!sendMailSsl.hasAllInformation()) {
|
||||||
player.sendMessage("Cannot register: no email address is set for the server. "
|
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||||
+ "Please contact an administrator");
|
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
|
||||||
ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set "
|
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
||||||
+ "to send emails from. Please add one in your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,9 @@ import org.bukkit.entity.Player;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for a player to unregister himself.
|
||||||
|
*/
|
||||||
public class UnregisterCommand extends PlayerCommand {
|
public class UnregisterCommand extends PlayerCommand {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -24,15 +27,15 @@ public class UnregisterCommand extends PlayerCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void runCommand(Player player, List<String> arguments) {
|
public void runCommand(Player player, List<String> arguments) {
|
||||||
String playerPass = arguments.get(0);
|
String playerPass = arguments.get(0);
|
||||||
final String playerNameLowerCase = player.getName().toLowerCase();
|
final String playerName = player.getName();
|
||||||
|
|
||||||
// Make sure the player is authenticated
|
// Make sure the player is authenticated
|
||||||
if (!playerCache.isAuthenticated(playerNameLowerCase)) {
|
if (!playerCache.isAuthenticated(playerName)) {
|
||||||
commandService.send(player, MessageKey.NOT_LOGGED_IN);
|
commandService.send(player, MessageKey.NOT_LOGGED_IN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregister the player
|
// Unregister the player
|
||||||
management.performUnregister(player, playerPass, false);
|
management.performUnregister(player, playerPass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import fr.xephi.authme.initialization.SettingsDependent;
|
|||||||
import fr.xephi.authme.permission.DefaultPermission;
|
import fr.xephi.authme.permission.DefaultPermission;
|
||||||
import fr.xephi.authme.permission.PermissionNode;
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -48,9 +48,9 @@ public class HelpProvider implements SettingsDependent {
|
|||||||
private String helpHeader;
|
private String helpHeader;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
|
HelpProvider(PermissionsManager permissionsManager, Settings settings) {
|
||||||
this.permissionsManager = permissionsManager;
|
this.permissionsManager = permissionsManager;
|
||||||
loadSettings(settings);
|
reload(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
|
private List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
|
||||||
@ -102,7 +102,7 @@ public class HelpProvider implements SettingsDependent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSettings(NewSetting settings) {
|
public void reload(Settings settings) {
|
||||||
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
|
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import fr.xephi.authme.ConsoleLogger;
|
|||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.ConverterSettings;
|
import fr.xephi.authme.settings.properties.ConverterSettings;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
@ -20,11 +20,11 @@ import java.io.IOException;
|
|||||||
public class CrazyLoginConverter implements Converter {
|
public class CrazyLoginConverter implements Converter {
|
||||||
|
|
||||||
private final DataSource database;
|
private final DataSource database;
|
||||||
private final NewSetting settings;
|
private final Settings settings;
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings) {
|
CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings) {
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
this.database = dataSource;
|
this.database = dataSource;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
@ -61,7 +61,7 @@ public class CrazyLoginConverter implements Converter {
|
|||||||
}
|
}
|
||||||
ConsoleLogger.info("CrazyLogin database has been imported correctly");
|
ConsoleLogger.info("CrazyLogin database has been imported correctly");
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError("Can't open the crazylogin database file! Does it exist?");
|
ConsoleLogger.warning("Can't open the crazylogin database file! Does it exist?");
|
||||||
ConsoleLogger.logException("Encountered", ex);
|
ConsoleLogger.logException("Encountered", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public class ForceFlatToSqlite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!skippedPlayers.isEmpty()) {
|
if (!skippedPlayers.isEmpty()) {
|
||||||
ConsoleLogger.showError("Warning: skipped conversion for players which were already in SQLite: "
|
ConsoleLogger.warning("Warning: skipped conversion for players which were already in SQLite: "
|
||||||
+ StringUtils.join(", ", skippedPlayers));
|
+ StringUtils.join(", ", skippedPlayers));
|
||||||
}
|
}
|
||||||
ConsoleLogger.info("Database successfully converted from " + source.getClass().getSimpleName()
|
ConsoleLogger.info("Database successfully converted from " + source.getClass().getSimpleName()
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import fr.xephi.authme.datasource.DataSource;
|
|||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.ConverterSettings;
|
import fr.xephi.authme.settings.properties.ConverterSettings;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
@ -24,12 +24,12 @@ import java.util.Map.Entry;
|
|||||||
public class RakamakConverter implements Converter {
|
public class RakamakConverter implements Converter {
|
||||||
|
|
||||||
private final DataSource database;
|
private final DataSource database;
|
||||||
private final NewSetting settings;
|
private final Settings settings;
|
||||||
private final File pluginFolder;
|
private final File pluginFolder;
|
||||||
private final PasswordSecurity passwordSecurity;
|
private final PasswordSecurity passwordSecurity;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings,
|
RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings,
|
||||||
PasswordSecurity passwordSecurity) {
|
PasswordSecurity passwordSecurity) {
|
||||||
this.database = dataSource;
|
this.database = dataSource;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
@ -82,15 +82,14 @@ public class RakamakConverter implements Converter {
|
|||||||
.realName(playerName)
|
.realName(playerName)
|
||||||
.ip(ip)
|
.ip(ip)
|
||||||
.password(psw)
|
.password(psw)
|
||||||
.lastLogin(System.currentTimeMillis())
|
.lastLogin(0)
|
||||||
.build();
|
.build();
|
||||||
database.saveAuth(auth);
|
database.saveAuth(auth);
|
||||||
}
|
}
|
||||||
ConsoleLogger.info("Rakamak database has been imported correctly");
|
ConsoleLogger.info("Rakamak database has been imported correctly");
|
||||||
sender.sendMessage("Rakamak database has been imported correctly");
|
sender.sendMessage("Rakamak database has been imported correctly");
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.logException("Can't open the rakamak database file! Does it exist?", ex);
|
||||||
sender.sendMessage("Can't open the rakamak database file! Does it exist?");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,19 +7,19 @@ import fr.xephi.authme.datasource.DataSourceType;
|
|||||||
import fr.xephi.authme.datasource.SQLite;
|
import fr.xephi.authme.datasource.SQLite;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class SqliteToSql implements Converter {
|
public class SqliteToSql implements Converter {
|
||||||
|
|
||||||
private final NewSetting settings;
|
private final Settings settings;
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final Messages messages;
|
private final Messages messages;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SqliteToSql(NewSetting settings, DataSource dataSource, Messages messages) {
|
SqliteToSql(Settings settings, DataSource dataSource, Messages messages) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
|
|||||||
@ -1,28 +1,77 @@
|
|||||||
package fr.xephi.authme.converter;
|
package fr.xephi.authme.converter;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.util.StringUtils.makePath;
|
||||||
|
|
||||||
public class vAuthConverter implements Converter {
|
public class vAuthConverter implements Converter {
|
||||||
|
|
||||||
private final AuthMe plugin;
|
private final DataSource dataSource;
|
||||||
|
private final File vAuthPasswordsFile;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
vAuthConverter(AuthMe plugin) {
|
vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
||||||
this.plugin = plugin;
|
vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
|
||||||
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender) {
|
public void execute(CommandSender sender) {
|
||||||
try {
|
try (Scanner scanner = new Scanner(vAuthPasswordsFile)) {
|
||||||
new vAuthFileReader(plugin).convert();
|
while (scanner.hasNextLine()) {
|
||||||
} catch (Exception e) {
|
String line = scanner.nextLine();
|
||||||
sender.sendMessage(e.getMessage());
|
String name = line.split(": ")[0];
|
||||||
ConsoleLogger.showError(e.getMessage());
|
String password = line.split(": ")[1];
|
||||||
|
PlayerAuth auth;
|
||||||
|
if (isUuidInstance(password)) {
|
||||||
|
String pname;
|
||||||
|
try {
|
||||||
|
pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName();
|
||||||
|
} catch (Exception | NoSuchMethodError e) {
|
||||||
|
pname = getName(UUID.fromString(name));
|
||||||
|
}
|
||||||
|
if (pname == null)
|
||||||
|
continue;
|
||||||
|
auth = PlayerAuth.builder()
|
||||||
|
.name(pname.toLowerCase())
|
||||||
|
.realName(pname)
|
||||||
|
.password(password, null).build();
|
||||||
|
} else {
|
||||||
|
auth = PlayerAuth.builder()
|
||||||
|
.name(name.toLowerCase())
|
||||||
|
.realName(name)
|
||||||
|
.password(password, null).build();
|
||||||
|
}
|
||||||
|
dataSource.saveAuth(auth);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ConsoleLogger.logException("Error while trying to import some vAuth data", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isUuidInstance(String s) {
|
||||||
|
return s.length() > 8 && s.charAt(8) == '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getName(UUID uuid) {
|
||||||
|
for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
|
||||||
|
if (op.getUniqueId().compareTo(uuid) == 0) {
|
||||||
|
return op.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
package fr.xephi.authme.converter;
|
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.util.StringUtils.makePath;
|
|
||||||
|
|
||||||
class vAuthFileReader {
|
|
||||||
|
|
||||||
private final AuthMe plugin;
|
|
||||||
private final DataSource database;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for vAuthFileReader.
|
|
||||||
*
|
|
||||||
* @param plugin AuthMe
|
|
||||||
*/
|
|
||||||
public vAuthFileReader(AuthMe plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.database = plugin.getDataSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void convert() {
|
|
||||||
final File file = new File(plugin.getDataFolder().getParent(), makePath("vAuth", "passwords.yml"));
|
|
||||||
Scanner scanner;
|
|
||||||
try {
|
|
||||||
scanner = new Scanner(file);
|
|
||||||
while (scanner.hasNextLine()) {
|
|
||||||
String line = scanner.nextLine();
|
|
||||||
String name = line.split(": ")[0];
|
|
||||||
String password = line.split(": ")[1];
|
|
||||||
PlayerAuth auth;
|
|
||||||
if (isUuidInstance(password)) {
|
|
||||||
String pname;
|
|
||||||
try {
|
|
||||||
pname = Bukkit.getOfflinePlayer(UUID.fromString(name)).getName();
|
|
||||||
} catch (Exception | NoSuchMethodError e) {
|
|
||||||
pname = getName(UUID.fromString(name));
|
|
||||||
}
|
|
||||||
if (pname == null)
|
|
||||||
continue;
|
|
||||||
auth = PlayerAuth.builder()
|
|
||||||
.name(pname.toLowerCase())
|
|
||||||
.realName(pname)
|
|
||||||
.password(password, null).build();
|
|
||||||
} else {
|
|
||||||
auth = PlayerAuth.builder()
|
|
||||||
.name(name.toLowerCase())
|
|
||||||
.realName(name)
|
|
||||||
.password(password, null).build();
|
|
||||||
}
|
|
||||||
database.saveAuth(auth);
|
|
||||||
}
|
|
||||||
scanner.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
ConsoleLogger.logException("Error while trying to import some vAuth data", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isUuidInstance(String s) {
|
|
||||||
return s.length() > 8 && s.charAt(8) == '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getName(UUID uuid) {
|
|
||||||
for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
|
|
||||||
if (op.getUniqueId().compareTo(uuid) == 0) {
|
|
||||||
return op.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,28 +1,146 @@
|
|||||||
package fr.xephi.authme.converter;
|
package fr.xephi.authme.converter;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
import de.luricos.bukkit.xAuth.database.DatabaseTables;
|
||||||
|
import de.luricos.bukkit.xAuth.utils.xAuthLog;
|
||||||
|
import de.luricos.bukkit.xAuth.xAuth;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.util.CollectionUtils;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.util.StringUtils.makePath;
|
||||||
|
|
||||||
public class xAuthConverter implements Converter {
|
public class xAuthConverter implements Converter {
|
||||||
|
|
||||||
private final AuthMe plugin;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
xAuthConverter(AuthMe plugin) {
|
@DataFolder
|
||||||
this.plugin = plugin;
|
private File dataFolder;
|
||||||
|
@Inject
|
||||||
|
private DataSource database;
|
||||||
|
@Inject
|
||||||
|
private PluginManager pluginManager;
|
||||||
|
|
||||||
|
xAuthConverter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender) {
|
public void execute(CommandSender sender) {
|
||||||
try {
|
try {
|
||||||
Class.forName("de.luricos.bukkit.xAuth.xAuth");
|
Class.forName("de.luricos.bukkit.xAuth.xAuth");
|
||||||
xAuthToFlat converter = new xAuthToFlat(plugin, sender);
|
convert(sender);
|
||||||
converter.convert();
|
|
||||||
} catch (ClassNotFoundException ce) {
|
} catch (ClassNotFoundException ce) {
|
||||||
sender.sendMessage("xAuth has not been found, please put xAuth.jar in your plugin folder and restart!");
|
sender.sendMessage("xAuth has not been found, please put xAuth.jar in your plugin folder and restart!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void convert(CommandSender sender) {
|
||||||
|
if (pluginManager.getPlugin("xAuth") == null) {
|
||||||
|
sender.sendMessage("[AuthMe] xAuth plugin not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO ljacqu 20160702: xAuthDb is not used except for the existence check -- is this intended?
|
||||||
|
File xAuthDb = new File(dataFolder.getParent(), makePath("xAuth", "xAuth.h2.db"));
|
||||||
|
if (!xAuthDb.exists()) {
|
||||||
|
sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
|
||||||
|
}
|
||||||
|
List<Integer> players = getXAuthPlayers();
|
||||||
|
if (CollectionUtils.isEmpty(players)) {
|
||||||
|
sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sender.sendMessage("[AuthMe] Starting import...");
|
||||||
|
|
||||||
|
for (int id : players) {
|
||||||
|
String pl = getIdPlayer(id);
|
||||||
|
String psw = getPassword(id);
|
||||||
|
if (psw != null && !psw.isEmpty() && pl != null) {
|
||||||
|
PlayerAuth auth = PlayerAuth.builder()
|
||||||
|
.name(pl.toLowerCase())
|
||||||
|
.realName(pl)
|
||||||
|
.password(psw, null).build();
|
||||||
|
database.saveAuth(auth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage("[AuthMe] Successfully converted from xAuth database");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getIdPlayer(int id) {
|
||||||
|
String realPass = "";
|
||||||
|
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?",
|
||||||
|
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
||||||
|
ps = conn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, id);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
if (!rs.next())
|
||||||
|
return null;
|
||||||
|
realPass = rs.getString("playername").toLowerCase();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
xAuthLog.severe("Failed to retrieve name for account: " + id, e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
||||||
|
}
|
||||||
|
return realPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getXAuthPlayers() {
|
||||||
|
List<Integer> xP = new ArrayList<>();
|
||||||
|
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = String.format("SELECT * FROM `%s`",
|
||||||
|
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
||||||
|
ps = conn.prepareStatement(sql);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
while (rs.next()) {
|
||||||
|
xP.add(rs.getInt("id"));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
xAuthLog.severe("Cannot import xAuthPlayers", e);
|
||||||
|
return new ArrayList<>();
|
||||||
|
} finally {
|
||||||
|
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
||||||
|
}
|
||||||
|
return xP;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPassword(int accountId) {
|
||||||
|
String realPass = "";
|
||||||
|
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?",
|
||||||
|
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
||||||
|
ps = conn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, accountId);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
if (!rs.next())
|
||||||
|
return null;
|
||||||
|
realPass = rs.getString("password");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
||||||
|
}
|
||||||
|
return realPass;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,136 +0,0 @@
|
|||||||
package fr.xephi.authme.converter;
|
|
||||||
|
|
||||||
import de.luricos.bukkit.xAuth.database.DatabaseTables;
|
|
||||||
import de.luricos.bukkit.xAuth.utils.xAuthLog;
|
|
||||||
import de.luricos.bukkit.xAuth.xAuth;
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
class xAuthToFlat {
|
|
||||||
|
|
||||||
private final AuthMe instance;
|
|
||||||
private final DataSource database;
|
|
||||||
private final CommandSender sender;
|
|
||||||
|
|
||||||
public xAuthToFlat(AuthMe instance, CommandSender sender) {
|
|
||||||
this.instance = instance;
|
|
||||||
this.database = instance.getDataSource();
|
|
||||||
this.sender = sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean convert() {
|
|
||||||
if (instance.getServer().getPluginManager().getPlugin("xAuth") == null) {
|
|
||||||
sender.sendMessage("[AuthMe] xAuth plugin not found");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
File xAuthDb = new File(instance.getDataFolder().getParent(), "xAuth" + File.separator + "xAuth.h2.db");
|
|
||||||
if (!xAuthDb.exists()) {
|
|
||||||
sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
|
|
||||||
}
|
|
||||||
List<Integer> players = getXAuthPlayers();
|
|
||||||
if (CollectionUtils.isEmpty(players)) {
|
|
||||||
sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sender.sendMessage("[AuthMe] Starting import...");
|
|
||||||
try {
|
|
||||||
for (int id : players) {
|
|
||||||
String pl = getIdPlayer(id);
|
|
||||||
String psw = getPassword(id);
|
|
||||||
if (psw != null && !psw.isEmpty() && pl != null) {
|
|
||||||
PlayerAuth auth = PlayerAuth.builder()
|
|
||||||
.name(pl.toLowerCase())
|
|
||||||
.realName(pl)
|
|
||||||
.password(psw, null).build();
|
|
||||||
database.saveAuth(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender.sendMessage("[AuthMe] Successfully converted from xAuth database");
|
|
||||||
} catch (Exception e) {
|
|
||||||
sender.sendMessage("[AuthMe] An error has occurred while importing the xAuth database."
|
|
||||||
+ " The import may have succeeded partially.");
|
|
||||||
ConsoleLogger.logException("Error during xAuth database import", e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getIdPlayer(int id) {
|
|
||||||
String realPass = "";
|
|
||||||
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
String sql = String.format("SELECT `playername` FROM `%s` WHERE `id` = ?",
|
|
||||||
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
|
||||||
ps = conn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, id);
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
if (!rs.next())
|
|
||||||
return null;
|
|
||||||
realPass = rs.getString("playername").toLowerCase();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
xAuthLog.severe("Failed to retrieve name for account: " + id, e);
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
|
||||||
}
|
|
||||||
return realPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Integer> getXAuthPlayers() {
|
|
||||||
List<Integer> xP = new ArrayList<>();
|
|
||||||
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
String sql = String.format("SELECT * FROM `%s`",
|
|
||||||
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
|
||||||
ps = conn.prepareStatement(sql);
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
while (rs.next()) {
|
|
||||||
xP.add(rs.getInt("id"));
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
xAuthLog.severe("Cannot import xAuthPlayers", e);
|
|
||||||
return new ArrayList<>();
|
|
||||||
} finally {
|
|
||||||
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
|
||||||
}
|
|
||||||
return xP;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPassword(int accountId) {
|
|
||||||
String realPass = "";
|
|
||||||
Connection conn = xAuth.getPlugin().getDatabaseController().getConnection();
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?",
|
|
||||||
xAuth.getPlugin().getDatabaseController().getTable(DatabaseTables.ACCOUNT));
|
|
||||||
ps = conn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, accountId);
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
if (!rs.next())
|
|
||||||
return null;
|
|
||||||
realPass = rs.getString("password");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e);
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
xAuth.getPlugin().getDatabaseController().close(conn, ps, rs);
|
|
||||||
}
|
|
||||||
return realPass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,6 +15,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
|
|||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@ -54,7 +55,6 @@ public class CacheDataSource implements DataSource {
|
|||||||
return executorService.submit(new Callable<Optional<PlayerAuth>>() {
|
return executorService.submit(new Callable<Optional<PlayerAuth>>() {
|
||||||
@Override
|
@Override
|
||||||
public Optional<PlayerAuth> call() {
|
public Optional<PlayerAuth> call() {
|
||||||
ConsoleLogger.debug("REFRESH " + key);
|
|
||||||
return load(key);
|
return load(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -139,13 +139,8 @@ public class CacheDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> autoPurgeDatabase(long until) {
|
public Set<String> getRecordsToPurge(long until) {
|
||||||
Set<String> cleared = source.autoPurgeDatabase(until);
|
return source.getRecordsToPurge(until);
|
||||||
for (String name : cleared) {
|
|
||||||
cachedAuths.invalidate(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleared;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -160,14 +155,14 @@ public class CacheDataSource implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
source.close();
|
|
||||||
cachedAuths.invalidateAll();
|
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
try {
|
try {
|
||||||
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
ConsoleLogger.writeStackTrace(e);
|
ConsoleLogger.logException("Could not close executor service:", e);
|
||||||
}
|
}
|
||||||
|
cachedAuths.invalidateAll();
|
||||||
|
source.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,8 +185,8 @@ public class CacheDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void purgeBanned(final Set<String> banned) {
|
public void purgeRecords(final Collection<String> banned) {
|
||||||
source.purgeBanned(banned);
|
source.purgeRecords(banned);
|
||||||
cachedAuths.invalidateAll(banned);
|
cachedAuths.invalidateAll(banned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,15 +230,6 @@ public class CacheDataSource implements DataSource {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateIp(String user, String ip) {
|
|
||||||
boolean result = source.updateIp(user, ip);
|
|
||||||
if (result) {
|
|
||||||
cachedAuths.refresh(user);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PlayerAuth> getAllAuths() {
|
public List<PlayerAuth> getAllAuths() {
|
||||||
return source.getAllAuths();
|
return source.getAllAuths();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package fr.xephi.authme.datasource;
|
package fr.xephi.authme.datasource;
|
||||||
|
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,7 +23,7 @@ public final class Columns {
|
|||||||
public final String ID;
|
public final String ID;
|
||||||
public final String IS_LOGGED;
|
public final String IS_LOGGED;
|
||||||
|
|
||||||
public Columns(NewSetting settings) {
|
public Columns(Settings settings) {
|
||||||
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
|
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
|
||||||
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
|
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
|
||||||
PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD);
|
PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
|
|||||||
import fr.xephi.authme.initialization.Reloadable;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -70,13 +71,19 @@ public interface DataSource extends Reloadable {
|
|||||||
boolean updatePassword(String user, HashedPassword password);
|
boolean updatePassword(String user, HashedPassword password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purge all records in the database whose last login was longer ago than
|
* Get all records in the database whose last login was before the given time.
|
||||||
* the given time.
|
|
||||||
*
|
*
|
||||||
* @param until The minimum last login
|
* @param until The minimum last login
|
||||||
* @return The account names that have been removed
|
* @return The account names selected to purge
|
||||||
*/
|
*/
|
||||||
Set<String> autoPurgeDatabase(long until);
|
Set<String> getRecordsToPurge(long until);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge the given players from the database.
|
||||||
|
*
|
||||||
|
* @param toPurge The players to purge
|
||||||
|
*/
|
||||||
|
void purgeRecords(Collection<String> toPurge);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a user record from the database.
|
* Remove a user record from the database.
|
||||||
@ -123,13 +130,6 @@ public interface DataSource extends Reloadable {
|
|||||||
*/
|
*/
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge all given players, i.e. delete all players whose name is in the list.
|
|
||||||
*
|
|
||||||
* @param banned the list of players to delete
|
|
||||||
*/
|
|
||||||
void purgeBanned(Set<String> banned);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the data source type.
|
* Return the data source type.
|
||||||
*
|
*
|
||||||
@ -187,15 +187,6 @@ public interface DataSource extends Reloadable {
|
|||||||
*/
|
*/
|
||||||
boolean updateRealName(String user, String realName);
|
boolean updateRealName(String user, String realName);
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a player's IP address.
|
|
||||||
*
|
|
||||||
* @param user The name of the user (lowercase)
|
|
||||||
* @param ip The IP address to save
|
|
||||||
* @return True upon success, false upon failure
|
|
||||||
*/
|
|
||||||
boolean updateIp(String user, String ip);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all players of the database.
|
* Return all players of the database.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
package fr.xephi.authme.datasource;
|
package fr.xephi.authme.datasource;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.settings.Settings;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
@ -17,6 +14,7 @@ import java.io.FileReader;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -41,27 +39,11 @@ public class FlatFile implements DataSource {
|
|||||||
*/
|
*/
|
||||||
private final File source;
|
private final File source;
|
||||||
|
|
||||||
public FlatFile() {
|
public FlatFile(File source) throws IOException {
|
||||||
AuthMe instance = AuthMe.getInstance();
|
|
||||||
|
|
||||||
source = new File(instance.getDataFolder(), "auths.db");
|
|
||||||
try {
|
|
||||||
source.createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
ConsoleLogger.logException("Cannot open flatfile", e);
|
|
||||||
if (Settings.isStopEnabled) {
|
|
||||||
ConsoleLogger.showError("Can't use FLAT FILE... SHUTDOWN...");
|
|
||||||
instance.getServer().shutdown();
|
|
||||||
}
|
|
||||||
if (!Settings.isStopEnabled) {
|
|
||||||
instance.getServer().getPluginManager().disablePlugin(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public FlatFile(File source) {
|
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
if (!source.exists() && !source.createNewFile()) {
|
||||||
|
throw new IOException("Could not create file '" + source.getPath() + "'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,7 +64,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -109,7 +91,7 @@ public class FlatFile implements DataSource {
|
|||||||
bw = new BufferedWriter(new FileWriter(source, true));
|
bw = new BufferedWriter(new FileWriter(source, true));
|
||||||
bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
|
bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(bw);
|
silentClose(bw);
|
||||||
@ -145,7 +127,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -179,7 +161,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -216,7 +198,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -229,11 +211,10 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> autoPurgeDatabase(long until) {
|
public Set<String> getRecordsToPurge(long until) {
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
BufferedWriter bw = null;
|
Set<String> list = new HashSet<>();
|
||||||
ArrayList<String> lines = new ArrayList<>();
|
|
||||||
Set<String> cleared = new HashSet<>();
|
|
||||||
try {
|
try {
|
||||||
br = new BufferedReader(new FileReader(source));
|
br = new BufferedReader(new FileReader(source));
|
||||||
String line;
|
String line;
|
||||||
@ -241,25 +222,24 @@ public class FlatFile implements DataSource {
|
|||||||
String[] args = line.split(":");
|
String[] args = line.split(":");
|
||||||
if (args.length >= 4) {
|
if (args.length >= 4) {
|
||||||
if (Long.parseLong(args[3]) >= until) {
|
if (Long.parseLong(args[3]) >= until) {
|
||||||
lines.add(line);
|
list.add(args[0]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleared.add(args[0]);
|
|
||||||
}
|
|
||||||
bw = new BufferedWriter(new FileWriter(source));
|
|
||||||
for (String l : lines) {
|
|
||||||
bw.write(l + "\n");
|
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return cleared;
|
return list;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
silentClose(bw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cleared;
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void purgeRecords(Collection<String> toPurge) {
|
||||||
|
throw new UnsupportedOperationException("Flat file no longer supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -284,7 +264,7 @@ public class FlatFile implements DataSource {
|
|||||||
bw.write(l + "\n");
|
bw.write(l + "\n");
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -306,7 +286,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -339,10 +319,10 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
if (br != null) {
|
if (br != null) {
|
||||||
@ -374,10 +354,10 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
return countIp;
|
return countIp;
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
} finally {
|
} finally {
|
||||||
if (br != null) {
|
if (br != null) {
|
||||||
@ -404,7 +384,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
return countEmail;
|
return countEmail;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
if (br != null) {
|
if (br != null) {
|
||||||
try {
|
try {
|
||||||
@ -416,37 +396,6 @@ public class FlatFile implements DataSource {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void purgeBanned(Set<String> banned) {
|
|
||||||
BufferedReader br = null;
|
|
||||||
BufferedWriter bw = null;
|
|
||||||
ArrayList<String> lines = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
br = new BufferedReader(new FileReader(source));
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
String[] args = line.split(":");
|
|
||||||
try {
|
|
||||||
if (banned.contains(args[0])) {
|
|
||||||
lines.add(line);
|
|
||||||
}
|
|
||||||
} catch (NullPointerException | ArrayIndexOutOfBoundsException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bw = new BufferedWriter(new FileWriter(source));
|
|
||||||
for (String l : lines) {
|
|
||||||
bw.write(l + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
silentClose(br);
|
|
||||||
silentClose(bw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceType getType() {
|
||||||
return DataSourceType.FILE;
|
return DataSourceType.FILE;
|
||||||
@ -479,7 +428,7 @@ public class FlatFile implements DataSource {
|
|||||||
result++;
|
result++;
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
} finally {
|
||||||
silentClose(br);
|
silentClose(br);
|
||||||
@ -492,11 +441,6 @@ public class FlatFile implements DataSource {
|
|||||||
throw new UnsupportedOperationException("Flat file no longer supported");
|
throw new UnsupportedOperationException("Flat file no longer supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateIp(String user, String ip) {
|
|
||||||
throw new UnsupportedOperationException("Flat file no longer supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PlayerAuth> getAllAuths() {
|
public List<PlayerAuth> getAllAuths() {
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
|
|||||||
@ -3,13 +3,11 @@ package fr.xephi.authme.datasource;
|
|||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
|
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.security.HashAlgorithm;
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.security.crypts.XFBCRYPT;
|
import fr.xephi.authme.security.crypts.XFBCRYPT;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
@ -25,72 +23,65 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class MySQL implements DataSource {
|
public class MySQL implements DataSource {
|
||||||
|
|
||||||
private final String host;
|
private String host;
|
||||||
private final String port;
|
private String port;
|
||||||
private final String username;
|
private String username;
|
||||||
private final String password;
|
private String password;
|
||||||
private final String database;
|
private String database;
|
||||||
private final String tableName;
|
private String tableName;
|
||||||
private final List<String> columnOthers;
|
private List<String> columnOthers;
|
||||||
private final Columns col;
|
private Columns col;
|
||||||
private final HashAlgorithm hashAlgorithm;
|
private HashAlgorithm hashAlgorithm;
|
||||||
private HikariDataSource ds;
|
private HikariDataSource ds;
|
||||||
|
|
||||||
private final String phpBbPrefix;
|
private String phpBbPrefix;
|
||||||
private final int phpBbGroup;
|
private int phpBbGroup;
|
||||||
private final String wordpressPrefix;
|
private String wordpressPrefix;
|
||||||
|
|
||||||
public MySQL(NewSetting settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
|
public MySQL(Settings settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
|
||||||
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
|
setParameters(settings);
|
||||||
this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
|
|
||||||
this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
|
|
||||||
this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
|
|
||||||
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
|
||||||
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
|
||||||
this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS);
|
|
||||||
this.col = new Columns(settings);
|
|
||||||
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.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
|
||||||
|
|
||||||
// Set the connection arguments (and check if connection is ok)
|
// Set the connection arguments (and check if connection is ok)
|
||||||
try {
|
try {
|
||||||
this.setConnectionArguments();
|
this.setConnectionArguments();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if (e instanceof IllegalArgumentException) {
|
if (e instanceof IllegalArgumentException) {
|
||||||
ConsoleLogger.showError("Invalid database arguments! Please check your configuration!");
|
ConsoleLogger.warning("Invalid database arguments! Please check your configuration!");
|
||||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
ConsoleLogger.warning("If this error persists, please report it to the developer!");
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
}
|
||||||
if (e instanceof PoolInitializationException) {
|
if (e instanceof PoolInitializationException) {
|
||||||
ConsoleLogger.showError("Can't initialize database connection! Please check your configuration!");
|
ConsoleLogger.warning("Can't initialize database connection! Please check your configuration!");
|
||||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
ConsoleLogger.warning("If this error persists, please report it to the developer!");
|
||||||
throw new PoolInitializationException(e);
|
|
||||||
}
|
}
|
||||||
ConsoleLogger.showError("Can't use the Hikari Connection Pool! Please, report this error to the developer!");
|
ConsoleLogger.warning("Can't use the Hikari Connection Pool! Please, report this error to the developer!");
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the database
|
// Initialize the database
|
||||||
try {
|
try {
|
||||||
this.setupConnection();
|
checkTablesAndColumns();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
this.close();
|
close();
|
||||||
ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN...");
|
ConsoleLogger.logException("Can't initialize the MySQL database:", e);
|
||||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
ConsoleLogger.warning("Please check your database settings in the config.yml file!");
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
MySQL(NewSetting settings, HikariDataSource hikariDataSource) {
|
MySQL(Settings settings, HikariDataSource hikariDataSource) {
|
||||||
|
ds = hikariDataSource;
|
||||||
|
setParameters(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setParameters(Settings settings) {
|
||||||
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
|
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
|
||||||
this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
|
this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
|
||||||
this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
|
this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
|
||||||
@ -103,7 +94,6 @@ public class MySQL implements DataSource {
|
|||||||
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
|
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
|
||||||
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
|
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
|
||||||
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
||||||
ds = hikariDataSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConnectionArguments() throws RuntimeException {
|
private void setConnectionArguments() throws RuntimeException {
|
||||||
@ -147,118 +137,83 @@ public class MySQL implements DataSource {
|
|||||||
return ds.getConnection();
|
return ds.getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupConnection() throws SQLException {
|
private void checkTablesAndColumns() throws SQLException {
|
||||||
try (Connection con = getConnection()) {
|
try (Connection con = getConnection(); Statement st = con.createStatement()) {
|
||||||
Statement st = con.createStatement();
|
// Create table with ID column if it doesn't exist
|
||||||
DatabaseMetaData md = con.getMetaData();
|
|
||||||
// Create table if not exists.
|
|
||||||
String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " ("
|
String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " ("
|
||||||
+ col.ID + " INTEGER AUTO_INCREMENT,"
|
+ col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT,"
|
||||||
+ col.NAME + " VARCHAR(255) NOT NULL UNIQUE,"
|
+ "PRIMARY KEY (" + col.ID + ")"
|
||||||
+ col.REAL_NAME + " VARCHAR(255) NOT NULL,"
|
+ ") CHARACTER SET = utf8;";
|
||||||
+ col.PASSWORD + " VARCHAR(255) NOT NULL,"
|
|
||||||
+ col.IP + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1',"
|
|
||||||
+ col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0,"
|
|
||||||
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0',"
|
|
||||||
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0',"
|
|
||||||
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0',"
|
|
||||||
+ col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "',"
|
|
||||||
+ col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com',"
|
|
||||||
+ col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0',"
|
|
||||||
+ "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + ")"
|
|
||||||
+ ");";
|
|
||||||
st.executeUpdate(sql);
|
st.executeUpdate(sql);
|
||||||
|
|
||||||
ResultSet rs = md.getColumns(null, null, tableName, col.NAME);
|
DatabaseMetaData md = con.getMetaData();
|
||||||
if (!rs.next()) {
|
if (isColumnMissing(md, col.NAME)) {
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
+ " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";");
|
+ " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.REAL_NAME);
|
if (isColumnMissing(md, col.REAL_NAME)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
+ " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";");
|
+ " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.PASSWORD);
|
if (isColumnMissing(md, col.PASSWORD)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
+ " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;");
|
+ " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
|
|
||||||
if (!col.SALT.isEmpty()) {
|
|
||||||
rs = md.getColumns(null, null, tableName, col.SALT);
|
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
|
||||||
+ " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.IP);
|
if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isColumnMissing(md, col.IP)) {
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
+ " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
|
+ " ADD COLUMN " + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
|
if (isColumnMissing(md, col.LAST_LOGIN)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
+ " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;");
|
+ " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;");
|
||||||
} else {
|
} else {
|
||||||
migrateLastLoginColumnToBigInt(con, rs);
|
migrateLastLoginColumn(con, md);
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
|
if (isColumnMissing(md, col.LASTLOC_X)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||||
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD "
|
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD "
|
||||||
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_X + " , ADD "
|
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_X + " , ADD "
|
||||||
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y);
|
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y);
|
||||||
}
|
} else {
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
|
|
||||||
if (rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " MODIFY "
|
st.executeUpdate("ALTER TABLE " + tableName + " MODIFY "
|
||||||
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
|
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
|
||||||
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
|
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0', MODIFY "
|
||||||
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';");
|
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_WORLD);
|
if (isColumnMissing(md, col.LASTLOC_WORLD)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||||
+ col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z);
|
+ col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z);
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.EMAIL);
|
if (isColumnMissing(md, col.EMAIL)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||||
+ col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com' AFTER " + col.LASTLOC_WORLD);
|
+ col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com' AFTER " + col.LASTLOC_WORLD);
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
rs = md.getColumns(null, null, tableName, col.IS_LOGGED);
|
if (isColumnMissing(md, col.IS_LOGGED)) {
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||||
+ col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL);
|
+ col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL);
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
|
|
||||||
st.close();
|
|
||||||
}
|
}
|
||||||
ConsoleLogger.info("MySQL setup finished");
|
ConsoleLogger.info("MySQL setup finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
|
||||||
|
try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) {
|
||||||
|
return !rs.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAuthAvailable(String user) {
|
public boolean isAuthAvailable(String user) {
|
||||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
@ -613,21 +568,18 @@ public class MySQL implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> autoPurgeDatabase(long until) {
|
public Set<String> getRecordsToPurge(long until) {
|
||||||
Set<String> list = new HashSet<>();
|
Set<String> list = new HashSet<>();
|
||||||
|
|
||||||
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||||
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
|
||||||
try (Connection con = getConnection();
|
try (Connection con = getConnection();
|
||||||
PreparedStatement selectPst = con.prepareStatement(select);
|
PreparedStatement selectPst = con.prepareStatement(select)) {
|
||||||
PreparedStatement deletePst = con.prepareStatement(delete)) {
|
|
||||||
selectPst.setLong(1, until);
|
selectPst.setLong(1, until);
|
||||||
try (ResultSet rs = selectPst.executeQuery()) {
|
try (ResultSet rs = selectPst.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
list.add(rs.getString(col.NAME));
|
list.add(rs.getString(col.NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deletePst.setLong(1, until);
|
|
||||||
deletePst.executeUpdate();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -742,11 +694,11 @@ public class MySQL implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void purgeBanned(Set<String> banned) {
|
public void purgeRecords(Collection<String> toPurge) {
|
||||||
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
for (String name : banned) {
|
for (String name : toPurge) {
|
||||||
pst.setString(1, name);
|
pst.setString(1, name.toLowerCase());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@ -839,20 +791,6 @@ public class MySQL implements DataSource {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateIp(String user, String ip) {
|
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
|
|
||||||
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
|
||||||
pst.setString(1, ip);
|
|
||||||
pst.setString(2, user);
|
|
||||||
pst.executeUpdate();
|
|
||||||
return true;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
logSqlException(ex);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PlayerAuth> getAllAuths() {
|
public List<PlayerAuth> getAllAuths() {
|
||||||
List<PlayerAuth> auths = new ArrayList<>();
|
List<PlayerAuth> auths = new ArrayList<>();
|
||||||
@ -933,40 +871,82 @@ public class MySQL implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the lastlogin column is of type timestamp and, if so, revert it to the bigint format.
|
* Checks if the last login column has a type that needs to be migrated.
|
||||||
*
|
*
|
||||||
* @param con Connection to the database
|
* @param con connection to the database
|
||||||
* @param rs ResultSet containing meta data for the lastlogin column
|
* @param metaData lastlogin column meta data
|
||||||
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException {
|
private void migrateLastLoginColumn(Connection con, DatabaseMetaData metaData) throws SQLException {
|
||||||
final int columnType = rs.getInt("DATA_TYPE");
|
final int columnType;
|
||||||
if (columnType == Types.TIMESTAMP) {
|
try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) {
|
||||||
ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
|
if (!rs.next()) {
|
||||||
final String lastLoginOld = col.LAST_LOGIN + "_old";
|
ConsoleLogger.warning("Could not get LAST_LOGIN meta data. This should never happen!");
|
||||||
|
return;
|
||||||
// Rename lastlogin to lastlogin_old
|
}
|
||||||
String sql = String.format("ALTER TABLE %s CHANGE COLUMN %s %s BIGINT",
|
columnType = rs.getInt("DATA_TYPE");
|
||||||
tableName, col.LAST_LOGIN, lastLoginOld);
|
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.execute();
|
|
||||||
|
|
||||||
// Create lastlogin column
|
|
||||||
sql = String.format("ALTER TABLE %s ADD COLUMN %s "
|
|
||||||
+ "BIGINT NOT NULL DEFAULT 0 AFTER %s",
|
|
||||||
tableName, col.LAST_LOGIN, col.IP);
|
|
||||||
con.prepareStatement(sql).execute();
|
|
||||||
|
|
||||||
// Set values of lastlogin based on lastlogin_old
|
|
||||||
sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s)",
|
|
||||||
tableName, col.LAST_LOGIN, lastLoginOld);
|
|
||||||
con.prepareStatement(sql).execute();
|
|
||||||
|
|
||||||
// Drop lastlogin_old
|
|
||||||
sql = String.format("ALTER TABLE %s DROP COLUMN %s",
|
|
||||||
tableName, lastLoginOld);
|
|
||||||
con.prepareStatement(sql).execute();
|
|
||||||
ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (columnType == Types.TIMESTAMP) {
|
||||||
|
migrateLastLoginColumnFromTimestamp(con);
|
||||||
|
} else if (columnType == Types.INTEGER) {
|
||||||
|
migrateLastLoginColumnFromInt(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs conversion of lastlogin column from timestamp type to bigint.
|
||||||
|
*
|
||||||
|
* @param con connection to the database
|
||||||
|
*/
|
||||||
|
private void migrateLastLoginColumnFromTimestamp(Connection con) throws SQLException {
|
||||||
|
ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
|
||||||
|
final String lastLoginOld = col.LAST_LOGIN + "_old";
|
||||||
|
|
||||||
|
// Rename lastlogin to lastlogin_old
|
||||||
|
String sql = String.format("ALTER TABLE %s CHANGE COLUMN %s %s BIGINT",
|
||||||
|
tableName, col.LAST_LOGIN, lastLoginOld);
|
||||||
|
PreparedStatement pst = con.prepareStatement(sql);
|
||||||
|
pst.execute();
|
||||||
|
|
||||||
|
// Create lastlogin column
|
||||||
|
sql = String.format("ALTER TABLE %s ADD COLUMN %s "
|
||||||
|
+ "BIGINT NOT NULL DEFAULT 0 AFTER %s",
|
||||||
|
tableName, col.LAST_LOGIN, col.IP);
|
||||||
|
con.prepareStatement(sql).execute();
|
||||||
|
|
||||||
|
// Set values of lastlogin based on lastlogin_old
|
||||||
|
sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s) * 1000",
|
||||||
|
tableName, col.LAST_LOGIN, lastLoginOld);
|
||||||
|
con.prepareStatement(sql).execute();
|
||||||
|
|
||||||
|
// Drop lastlogin_old
|
||||||
|
sql = String.format("ALTER TABLE %s DROP COLUMN %s",
|
||||||
|
tableName, lastLoginOld);
|
||||||
|
con.prepareStatement(sql).execute();
|
||||||
|
ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs conversion of lastlogin column from int to bigint.
|
||||||
|
*
|
||||||
|
* @param con connection to the database
|
||||||
|
*/
|
||||||
|
private void migrateLastLoginColumnFromInt(Connection con) throws SQLException {
|
||||||
|
// Change from int to bigint
|
||||||
|
ConsoleLogger.info("Migrating lastlogin column from int to bigint");
|
||||||
|
String sql = String.format("ALTER TABLE %s MODIFY %s BIGINT;", tableName, col.LAST_LOGIN);
|
||||||
|
con.prepareStatement(sql).execute();
|
||||||
|
|
||||||
|
// Migrate timestamps in seconds format to milliseconds format if they are plausible
|
||||||
|
int rangeStart = 1262304000; // timestamp for 2010-01-01
|
||||||
|
int rangeEnd = 1514678400; // timestamp for 2017-12-31
|
||||||
|
sql = String.format("UPDATE %s SET %s = %s * 1000 WHERE %s > %d AND %s < %d;",
|
||||||
|
tableName, col.LAST_LOGIN, col.LAST_LOGIN, col.LAST_LOGIN, rangeStart, col.LAST_LOGIN, rangeEnd);
|
||||||
|
int changedRows = con.prepareStatement(sql).executeUpdate();
|
||||||
|
|
||||||
|
ConsoleLogger.warning("You may have entries with invalid timestamps. Please check your data "
|
||||||
|
+ "before purging. " + changedRows + " rows were migrated from seconds to milliseconds.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logSqlException(SQLException e) {
|
private static void logSqlException(SQLException e) {
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
package fr.xephi.authme.datasource;
|
package fr.xephi.authme.datasource;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
|
||||||
import fr.xephi.authme.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class SQLite implements DataSource {
|
public class SQLite implements DataSource {
|
||||||
@ -38,7 +38,7 @@ public class SQLite implements DataSource {
|
|||||||
* @throws ClassNotFoundException if no driver could be found for the datasource
|
* @throws ClassNotFoundException if no driver could be found for the datasource
|
||||||
* @throws SQLException when initialization of a SQL datasource failed
|
* @throws SQLException when initialization of a SQL datasource failed
|
||||||
*/
|
*/
|
||||||
public SQLite(NewSetting settings) throws ClassNotFoundException, SQLException {
|
public SQLite(Settings settings) throws ClassNotFoundException, SQLException {
|
||||||
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||||
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||||
this.col = new Columns(settings);
|
this.col = new Columns(settings);
|
||||||
@ -53,7 +53,7 @@ public class SQLite implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SQLite(NewSetting settings, Connection connection) {
|
SQLite(Settings settings, Connection connection) {
|
||||||
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||||
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||||
this.col = new Columns(settings);
|
this.col = new Columns(settings);
|
||||||
@ -70,67 +70,73 @@ public class SQLite implements DataSource {
|
|||||||
this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db");
|
this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setup() throws SQLException {
|
@VisibleForTesting
|
||||||
Statement st = null;
|
protected void setup() throws SQLException {
|
||||||
ResultSet rs = null;
|
try (Statement st = con.createStatement()) {
|
||||||
try {
|
// Note: cannot add unique fields later on in SQLite, so we add it on initialization
|
||||||
st = con.createStatement();
|
st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " ("
|
||||||
st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (" + col.ID + " INTEGER AUTO_INCREMENT," + col.NAME + " VARCHAR(255) NOT NULL UNIQUE," + col.PASSWORD + " VARCHAR(255) NOT NULL," + col.IP + " VARCHAR(40) NOT NULL," + col.LAST_LOGIN + " BIGINT," + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0'," + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT '" + Settings.defaultWorld + "'," + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com'," + "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));");
|
+ col.ID + " INTEGER AUTO_INCREMENT, "
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.PASSWORD);
|
+ col.NAME + " VARCHAR(255) NOT NULL UNIQUE, "
|
||||||
if (!rs.next()) {
|
+ "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));");
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;");
|
|
||||||
|
DatabaseMetaData md = con.getMetaData();
|
||||||
|
|
||||||
|
if (isColumnMissing(md, col.REAL_NAME)) {
|
||||||
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||||
|
+ col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
if (!col.SALT.isEmpty()) {
|
if (isColumnMissing(md, col.PASSWORD)) {
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.SALT);
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
if (!rs.next()) {
|
+ " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';");
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
}
|
}
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.IP);
|
|
||||||
if (!rs.next()) {
|
if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.LAST_LOGIN);
|
if (isColumnMissing(md, col.IP)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP DEFAULT current_timestamp;");
|
+ " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL DEFAULT '';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_X);
|
if (isColumnMissing(md, col.LAST_LOGIN)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0';");
|
+ " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;");
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0';");
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0';");
|
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_WORLD);
|
if (isColumnMissing(md, col.LASTLOC_X)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
|
+ " DOUBLE NOT NULL DEFAULT '0.0';");
|
||||||
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Y
|
||||||
|
+ " DOUBLE NOT NULL DEFAULT '0.0';");
|
||||||
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_Z
|
||||||
|
+ " DOUBLE NOT NULL DEFAULT '0.0';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.EMAIL);
|
if (isColumnMissing(md, col.LASTLOC_WORLD)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
|
+ " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.IS_LOGGED);
|
if (isColumnMissing(md, col.EMAIL)) {
|
||||||
if (!rs.next()) {
|
st.executeUpdate("ALTER TABLE " + tableName
|
||||||
|
+ " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isColumnMissing(md, col.IS_LOGGED)) {
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " INT DEFAULT '0';");
|
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IS_LOGGED + " INT DEFAULT '0';");
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
rs = con.getMetaData().getColumns(null, null, tableName, col.REAL_NAME);
|
|
||||||
if (!rs.next()) {
|
|
||||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL DEFAULT 'Player';");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
close(rs);
|
|
||||||
close(st);
|
|
||||||
}
|
}
|
||||||
ConsoleLogger.info("SQLite Setup finished");
|
ConsoleLogger.info("SQLite Setup finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
|
||||||
|
try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) {
|
||||||
|
return !rs.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reload() {
|
public void reload() {
|
||||||
close(con);
|
close(con);
|
||||||
@ -147,12 +153,12 @@ public class SQLite implements DataSource {
|
|||||||
PreparedStatement pst = null;
|
PreparedStatement pst = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);");
|
pst = con.prepareStatement("SELECT 1 FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);");
|
||||||
pst.setString(1, user);
|
pst.setString(1, user);
|
||||||
rs = pst.executeQuery();
|
rs = pst.executeQuery();
|
||||||
return rs.next();
|
return rs.next();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.warning(ex.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
close(rs);
|
close(rs);
|
||||||
@ -207,7 +213,7 @@ public class SQLite implements DataSource {
|
|||||||
HashedPassword password = auth.getPassword();
|
HashedPassword password = auth.getPassword();
|
||||||
if (col.SALT.isEmpty()) {
|
if (col.SALT.isEmpty()) {
|
||||||
if (!StringUtils.isEmpty(auth.getPassword().getSalt())) {
|
if (!StringUtils.isEmpty(auth.getPassword().getSalt())) {
|
||||||
ConsoleLogger.showError("Warning! Detected hashed password with separate salt but the salt column "
|
ConsoleLogger.warning("Warning! Detected hashed password with separate salt but the salt column "
|
||||||
+ "is not set in the config!");
|
+ "is not set in the config!");
|
||||||
}
|
}
|
||||||
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD +
|
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD +
|
||||||
@ -293,20 +299,17 @@ public class SQLite implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> autoPurgeDatabase(long until) {
|
public Set<String> getRecordsToPurge(long until) {
|
||||||
Set<String> list = new HashSet<>();
|
Set<String> list = new HashSet<>();
|
||||||
|
|
||||||
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||||
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
try (PreparedStatement selectPst = con.prepareStatement(select)) {
|
||||||
try (PreparedStatement selectPst = con.prepareStatement(select);
|
|
||||||
PreparedStatement deletePst = con.prepareStatement(delete)) {
|
|
||||||
selectPst.setLong(1, until);
|
selectPst.setLong(1, until);
|
||||||
try (ResultSet rs = selectPst.executeQuery()) {
|
try (ResultSet rs = selectPst.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
list.add(rs.getString(col.NAME));
|
list.add(rs.getString(col.NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deletePst.setLong(1, until);
|
|
||||||
deletePst.executeUpdate();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -314,6 +317,19 @@ public class SQLite implements DataSource {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void purgeRecords(Collection<String> toPurge) {
|
||||||
|
String delete = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
|
try (PreparedStatement deletePst = con.prepareStatement(delete)) {
|
||||||
|
for (String name : toPurge) {
|
||||||
|
deletePst.setString(1, name.toLowerCase());
|
||||||
|
deletePst.executeUpdate();
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
logSqlException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeAuth(String user) {
|
public boolean removeAuth(String user) {
|
||||||
PreparedStatement pst = null;
|
PreparedStatement pst = null;
|
||||||
@ -443,19 +459,6 @@ public class SQLite implements DataSource {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void purgeBanned(Set<String> banned) {
|
|
||||||
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
|
||||||
try (PreparedStatement pst = con.prepareStatement(sql)) {
|
|
||||||
for (String name : banned) {
|
|
||||||
pst.setString(1, name);
|
|
||||||
pst.executeUpdate();
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
logSqlException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceType getType() {
|
||||||
return DataSourceType.SQLITE;
|
return DataSourceType.SQLITE;
|
||||||
@ -553,20 +556,6 @@ public class SQLite implements DataSource {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean updateIp(String user, String ip) {
|
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
|
|
||||||
try (PreparedStatement pst = con.prepareStatement(sql)) {
|
|
||||||
pst.setString(1, ip);
|
|
||||||
pst.setString(2, user);
|
|
||||||
pst.executeUpdate();
|
|
||||||
return true;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
logSqlException(ex);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PlayerAuth> getAllAuths() {
|
public List<PlayerAuth> getAllAuths() {
|
||||||
List<PlayerAuth> auths = new ArrayList<>();
|
List<PlayerAuth> auths = new ArrayList<>();
|
||||||
|
|||||||
@ -2,21 +2,17 @@ package fr.xephi.authme.hooks;
|
|||||||
|
|
||||||
import com.google.common.io.ByteArrayDataInput;
|
import com.google.common.io.ByteArrayDataInput;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
||||||
public class BungeeCordMessage implements PluginMessageListener {
|
public class BungeeCordMessage implements PluginMessageListener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -28,9 +24,6 @@ public class BungeeCordMessage implements PluginMessageListener {
|
|||||||
@Inject
|
@Inject
|
||||||
private PlayerCache playerCache;
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthMe plugin;
|
|
||||||
|
|
||||||
BungeeCordMessage() { }
|
BungeeCordMessage() { }
|
||||||
|
|
||||||
|
|
||||||
@ -56,26 +49,13 @@ public class BungeeCordMessage implements PluginMessageListener {
|
|||||||
if ("login".equals(act)) {
|
if ("login".equals(act)) {
|
||||||
playerCache.updatePlayer(auth);
|
playerCache.updatePlayer(auth);
|
||||||
dataSource.setLogged(name);
|
dataSource.setLogged(name);
|
||||||
//START 03062016 sgdc3: should fix #731 but we need to recode this mess
|
ConsoleLogger.fine("Player " + auth.getNickname() + " has logged in from one of your server!");
|
||||||
if (plugin.sessions.containsKey(name)) {
|
|
||||||
plugin.sessions.get(name).cancel();
|
|
||||||
plugin.sessions.remove(name);
|
|
||||||
}
|
|
||||||
//END
|
|
||||||
|
|
||||||
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
|
|
||||||
ConsoleLogger.info("Player " + auth.getNickname() + " has logged in from one of your server!");
|
|
||||||
}
|
|
||||||
} else if ("logout".equals(act)) {
|
} else if ("logout".equals(act)) {
|
||||||
playerCache.removePlayer(name);
|
playerCache.removePlayer(name);
|
||||||
dataSource.setUnlogged(name);
|
dataSource.setUnlogged(name);
|
||||||
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
|
ConsoleLogger.fine("Player " + auth.getNickname() + " has logged out from one of your server!");
|
||||||
ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!");
|
|
||||||
}
|
|
||||||
} else if ("register".equals(act)) {
|
} else if ("register".equals(act)) {
|
||||||
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
|
ConsoleLogger.fine("Player " + auth.getNickname() + " has registered out from one of your server!");
|
||||||
ConsoleLogger.info("Player " + auth.getNickname() + " has registered out from one of your server!");
|
|
||||||
}
|
|
||||||
} else if ("changepassword".equals(act)) {
|
} else if ("changepassword".equals(act)) {
|
||||||
final String password = args[2];
|
final String password = args[2];
|
||||||
final String salt = args.length >= 4 ? args[3] : null;
|
final String salt = args.length >= 4 ? args[3] : null;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package fr.xephi.authme.hooks;
|
package fr.xephi.authme.hooks;
|
||||||
|
|
||||||
|
import ch.jalu.injector.annotations.NoFieldScan;
|
||||||
import com.earth2me.essentials.Essentials;
|
import com.earth2me.essentials.Essentials;
|
||||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||||
@ -17,6 +18,7 @@ import java.io.File;
|
|||||||
/**
|
/**
|
||||||
* Hooks into third-party plugins and allows to perform actions on them.
|
* Hooks into third-party plugins and allows to perform actions on them.
|
||||||
*/
|
*/
|
||||||
|
@NoFieldScan
|
||||||
public class PluginHooks {
|
public class PluginHooks {
|
||||||
|
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
|
|||||||
@ -1,324 +0,0 @@
|
|||||||
package fr.xephi.authme.initialization;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dependency injector of AuthMe: initializes and injects services and tasks.
|
|
||||||
* <p>
|
|
||||||
* Only constructor and field injection are supported, indicated with the JSR330
|
|
||||||
* {@link javax.inject.Inject @Inject} annotation.
|
|
||||||
* <p>
|
|
||||||
* {@link PostConstruct @PostConstruct} methods are recognized and invoked upon
|
|
||||||
* instantiation. Note that the parent classes are <i>not</i> scanned for such methods.
|
|
||||||
*/
|
|
||||||
public class AuthMeServiceInitializer {
|
|
||||||
|
|
||||||
private final Set<String> ALLOWED_PACKAGES;
|
|
||||||
private final Map<Class<?>, Object> objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param allowedPackages list of allowed packages. Only classes whose package
|
|
||||||
* starts with any of the given entries will be instantiated
|
|
||||||
*/
|
|
||||||
public AuthMeServiceInitializer(String... allowedPackages) {
|
|
||||||
ALLOWED_PACKAGES = ImmutableSet.copyOf(allowedPackages);
|
|
||||||
objects = new HashMap<>();
|
|
||||||
objects.put(getClass(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves or instantiates an object of the given type.
|
|
||||||
*
|
|
||||||
* @param clazz the class to retrieve the value for
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return object of the class' type
|
|
||||||
*/
|
|
||||||
public <T> T get(Class<T> clazz) {
|
|
||||||
return get(clazz, new HashSet<Class<?>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an object with a custom class (supertype). Use this for example to specify a
|
|
||||||
* concrete implementation of an interface or an abstract class.
|
|
||||||
*
|
|
||||||
* @param clazz the class to register the object for
|
|
||||||
* @param object the object
|
|
||||||
* @param <T> the class' type
|
|
||||||
*/
|
|
||||||
public <T> void register(Class<? super T> clazz, T object) {
|
|
||||||
if (objects.containsKey(clazz)) {
|
|
||||||
throw new IllegalStateException("There is already an object present for " + clazz);
|
|
||||||
}
|
|
||||||
Preconditions.checkNotNull(object);
|
|
||||||
objects.put(clazz, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Associate an annotation with a value.
|
|
||||||
*
|
|
||||||
* @param annotation the annotation
|
|
||||||
* @param value the value
|
|
||||||
*/
|
|
||||||
public void provide(Class<? extends Annotation> annotation, Object value) {
|
|
||||||
if (objects.containsKey(annotation)) {
|
|
||||||
throw new IllegalStateException("Annotation @" + annotation.getClass().getSimpleName()
|
|
||||||
+ " already registered");
|
|
||||||
}
|
|
||||||
Preconditions.checkNotNull(value);
|
|
||||||
objects.put(annotation, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of the given class and does <i>not</i> keep track of it afterwards,
|
|
||||||
* unlike {@link #get(Class)} (singleton scope).
|
|
||||||
*
|
|
||||||
* @param clazz the class to instantiate
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return new instance of class T
|
|
||||||
*/
|
|
||||||
public <T> T newInstance(Class<T> clazz) {
|
|
||||||
return instantiate(clazz, new HashSet<Class<?>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of the given class if available. This simply returns the instance if present and
|
|
||||||
* otherwise {@code null}. Calling this method will not instantiate anything.
|
|
||||||
*
|
|
||||||
* @param clazz the class to retrieve the instance for
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return instance or null if none available
|
|
||||||
*/
|
|
||||||
public <T> T getIfAvailable(Class<T> clazz) {
|
|
||||||
if (Annotation.class.isAssignableFrom(clazz)) {
|
|
||||||
throw new UnsupportedOperationException("Annotations may not be retrieved in this way!");
|
|
||||||
}
|
|
||||||
return clazz.cast(objects.get(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of the given class by retrieving it or by instantiating it if not yet present.
|
|
||||||
*
|
|
||||||
* @param clazz the class to retrieve a value for
|
|
||||||
* @param traversedClasses the list of traversed classes
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return instance or associated value (for annotations)
|
|
||||||
*/
|
|
||||||
private <T> T get(Class<T> clazz, Set<Class<?>> traversedClasses) {
|
|
||||||
if (Annotation.class.isAssignableFrom(clazz)) {
|
|
||||||
throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!");
|
|
||||||
} else if (objects.containsKey(clazz)) {
|
|
||||||
return clazz.cast(objects.get(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
// First time we come across clazz, need to instantiate it. Validate that we can do so
|
|
||||||
validatePackage(clazz);
|
|
||||||
validateInstantiable(clazz);
|
|
||||||
|
|
||||||
// Add the clazz to the list of traversed classes in a new Set, so each path we take has its own Set.
|
|
||||||
traversedClasses = new HashSet<>(traversedClasses);
|
|
||||||
traversedClasses.add(clazz);
|
|
||||||
T object = instantiate(clazz, traversedClasses);
|
|
||||||
storeObject(object);
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a reload on all applicable instances which are registered.
|
|
||||||
* Requires that the {@link NewSetting settings} instance be registered.
|
|
||||||
* <p>
|
|
||||||
* Note that the order in which these classes are reloaded is not guaranteed.
|
|
||||||
*/
|
|
||||||
public void performReloadOnServices() {
|
|
||||||
NewSetting settings = (NewSetting) objects.get(NewSetting.class);
|
|
||||||
if (settings == null) {
|
|
||||||
throw new IllegalStateException("Settings instance is null");
|
|
||||||
}
|
|
||||||
for (Object object : objects.values()) {
|
|
||||||
if (object instanceof Reloadable) {
|
|
||||||
((Reloadable) object).reload();
|
|
||||||
} else if (object instanceof SettingsDependent) {
|
|
||||||
((SettingsDependent) object).loadSettings(settings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates the given class by locating its @Inject elements and retrieving
|
|
||||||
* or instantiating the required instances.
|
|
||||||
*
|
|
||||||
* @param clazz the class to instantiate
|
|
||||||
* @param traversedClasses collection of classes already traversed
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return the instantiated object
|
|
||||||
*/
|
|
||||||
private <T> T instantiate(Class<T> clazz, Set<Class<?>> traversedClasses) {
|
|
||||||
Injection<T> injection = firstNotNull(
|
|
||||||
ConstructorInjection.provide(clazz), FieldInjection.provide(clazz), InstantiationFallback.provide(clazz));
|
|
||||||
if (injection == null) {
|
|
||||||
throw new IllegalStateException("Did not find injection method for " + clazz + ". Make sure you have "
|
|
||||||
+ "a constructor with @Inject or fields with @Inject. Fields with @Inject require "
|
|
||||||
+ "the default constructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
|
|
||||||
Object[] dependencies = resolveDependencies(injection, traversedClasses);
|
|
||||||
T object = injection.instantiateWith(dependencies);
|
|
||||||
executePostConstructMethod(object);
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the dependencies for the given class instantiation, i.e. returns a collection that satisfy
|
|
||||||
* the class' dependencies by retrieving elements or instantiating them where necessary.
|
|
||||||
*
|
|
||||||
* @param injection the injection parameters
|
|
||||||
* @param traversedClasses collection of traversed classes
|
|
||||||
* @return array with the parameters to use in the constructor
|
|
||||||
*/
|
|
||||||
private Object[] resolveDependencies(Injection<?> injection, Set<Class<?>> traversedClasses) {
|
|
||||||
Class<?>[] dependencies = injection.getDependencies();
|
|
||||||
Class<?>[] annotations = injection.getDependencyAnnotations();
|
|
||||||
Object[] values = new Object[dependencies.length];
|
|
||||||
for (int i = 0; i < dependencies.length; ++i) {
|
|
||||||
if (annotations[i] == null) {
|
|
||||||
values[i] = get(dependencies[i], traversedClasses);
|
|
||||||
} else {
|
|
||||||
Object value = objects.get(annotations[i]);
|
|
||||||
if (value == null) {
|
|
||||||
throw new IllegalStateException("Value for field with @" + annotations[i].getSimpleName()
|
|
||||||
+ " must be registered beforehand");
|
|
||||||
}
|
|
||||||
values[i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the given object with its class as key. Throws an exception if the key already has
|
|
||||||
* a value associated to it.
|
|
||||||
*
|
|
||||||
* @param object the object to store
|
|
||||||
*/
|
|
||||||
private void storeObject(Object object) {
|
|
||||||
if (objects.containsKey(object.getClass())) {
|
|
||||||
throw new IllegalStateException("There is already an object present for " + object.getClass());
|
|
||||||
}
|
|
||||||
Preconditions.checkNotNull(object);
|
|
||||||
objects.put(object.getClass(), object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates that none of the dependencies' types are present in the given collection
|
|
||||||
* of traversed classes. This prevents circular dependencies.
|
|
||||||
*
|
|
||||||
* @param dependencies the dependencies of the class
|
|
||||||
* @param traversedClasses the collection of traversed classes
|
|
||||||
*/
|
|
||||||
private static void validateInjectionHasNoCircularDependencies(Class<?>[] dependencies,
|
|
||||||
Set<Class<?>> traversedClasses) {
|
|
||||||
for (Class<?> clazz : dependencies) {
|
|
||||||
if (traversedClasses.contains(clazz)) {
|
|
||||||
throw new IllegalStateException("Found cyclic dependency - already traversed '" + clazz
|
|
||||||
+ "' (full traversal list: " + traversedClasses + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the package of a parameter type to ensure that it is part of the allowed packages.
|
|
||||||
* This ensures that we don't try to instantiate things that are beyond our reach in case some
|
|
||||||
* external parameter type has not been registered.
|
|
||||||
*
|
|
||||||
* @param clazz the class to validate
|
|
||||||
*/
|
|
||||||
private void validatePackage(Class<?> clazz) {
|
|
||||||
if (clazz.getPackage() == null) {
|
|
||||||
throw new IllegalStateException("Primitive types must be provided explicitly (or use an annotation).");
|
|
||||||
}
|
|
||||||
String packageName = clazz.getPackage().getName();
|
|
||||||
for (String allowedPackage : ALLOWED_PACKAGES) {
|
|
||||||
if (packageName.startsWith(allowedPackage)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Class " + clazz + " with package " + packageName + " is outside of the "
|
|
||||||
+ "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes an object's method annotated with {@link PostConstruct} if present.
|
|
||||||
* Throws an exception if there are multiple such methods, or if the method is static.
|
|
||||||
*
|
|
||||||
* @param object the object to execute the post construct method for
|
|
||||||
*/
|
|
||||||
private static void executePostConstructMethod(Object object) {
|
|
||||||
Method postConstructMethod = getAndValidatePostConstructMethod(object.getClass());
|
|
||||||
if (postConstructMethod != null) {
|
|
||||||
try {
|
|
||||||
postConstructMethod.setAccessible(true);
|
|
||||||
postConstructMethod.invoke(object);
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new UnsupportedOperationException("Error executing @PostConstruct method", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void validateInstantiable(Class<?> clazz) {
|
|
||||||
if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
|
|
||||||
throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate and locate the given class' post construct method. Returns {@code null} if none present.
|
|
||||||
*
|
|
||||||
* @param clazz the class to search
|
|
||||||
* @return post construct method, or null
|
|
||||||
*/
|
|
||||||
private static Method getAndValidatePostConstructMethod(Class<?> clazz) {
|
|
||||||
Method postConstructMethod = null;
|
|
||||||
for (Method method : clazz.getDeclaredMethods()) {
|
|
||||||
if (method.isAnnotationPresent(PostConstruct.class)) {
|
|
||||||
if (postConstructMethod != null) {
|
|
||||||
throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz);
|
|
||||||
} else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) {
|
|
||||||
throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. "
|
|
||||||
+ "Invalid method in " + clazz);
|
|
||||||
} else if (method.getReturnType() != void.class) {
|
|
||||||
throw new IllegalStateException("@PostConstruct method must have return type void. "
|
|
||||||
+ "Offending class: " + clazz);
|
|
||||||
} else {
|
|
||||||
postConstructMethod = method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return postConstructMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SafeVarargs
|
|
||||||
private static <T> Injection<T> firstNotNull(Provider<? extends Injection<T>>... providers) {
|
|
||||||
for (Provider<? extends Injection<T>> provider : providers) {
|
|
||||||
Injection<T> object = provider.get();
|
|
||||||
if (object != null) {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
package fr.xephi.authme.initialization;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Functionality for constructor injection.
|
|
||||||
*/
|
|
||||||
public class ConstructorInjection<T> implements Injection<T> {
|
|
||||||
|
|
||||||
private final Constructor<T> constructor;
|
|
||||||
|
|
||||||
private ConstructorInjection(Constructor<T> constructor) {
|
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencies() {
|
|
||||||
return constructor.getParameterTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencyAnnotations() {
|
|
||||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
|
||||||
Class<?>[] annotations = new Class<?>[parameterAnnotations.length];
|
|
||||||
for (int i = 0; i < parameterAnnotations.length; ++i) {
|
|
||||||
annotations[i] = parameterAnnotations[i].length > 0
|
|
||||||
? parameterAnnotations[i][0].annotationType()
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
return annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T instantiateWith(Object... values) {
|
|
||||||
validateNoNullValues(values);
|
|
||||||
try {
|
|
||||||
return constructor.newInstance(values);
|
|
||||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new UnsupportedOperationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Provider<ConstructorInjection<T>> provide(final Class<T> clazz) {
|
|
||||||
return new Provider<ConstructorInjection<T>>() {
|
|
||||||
@Override
|
|
||||||
public ConstructorInjection<T> get() {
|
|
||||||
Constructor<T> constructor = getInjectionConstructor(clazz);
|
|
||||||
return constructor == null ? null : new ConstructorInjection<>(constructor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the first found constructor annotated with {@link Inject} of the given class
|
|
||||||
* and marks it as accessible.
|
|
||||||
*
|
|
||||||
* @param clazz the class to process
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return injection constructor for the class, null if not applicable
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T> Constructor<T> getInjectionConstructor(Class<T> clazz) {
|
|
||||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
|
||||||
for (Constructor<?> constructor : constructors) {
|
|
||||||
if (constructor.isAnnotationPresent(Inject.class)) {
|
|
||||||
constructor.setAccessible(true);
|
|
||||||
return (Constructor<T>) constructor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void validateNoNullValues(Object[] array) {
|
|
||||||
for (Object entry : array) {
|
|
||||||
Preconditions.checkNotNull(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
package fr.xephi.authme.initialization;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Functionality for field injection.
|
|
||||||
*/
|
|
||||||
public class FieldInjection<T> implements Injection<T> {
|
|
||||||
|
|
||||||
private final Field[] fields;
|
|
||||||
private final Constructor<T> defaultConstructor;
|
|
||||||
|
|
||||||
private FieldInjection(Constructor<T> defaultConstructor, Collection<Field> fields) {
|
|
||||||
this.fields = fields.toArray(new Field[fields.size()]);
|
|
||||||
this.defaultConstructor = defaultConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencies() {
|
|
||||||
Class<?>[] types = new Class<?>[fields.length];
|
|
||||||
for (int i = 0; i < fields.length; ++i) {
|
|
||||||
types[i] = fields[i].getType();
|
|
||||||
}
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencyAnnotations() {
|
|
||||||
Class<?>[] annotations = new Class<?>[fields.length];
|
|
||||||
for (int i = 0; i < fields.length; ++i) {
|
|
||||||
annotations[i] = getFirstNonInjectAnnotation(fields[i]);
|
|
||||||
}
|
|
||||||
return annotations;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T instantiateWith(Object... values) {
|
|
||||||
Preconditions.checkArgument(values.length == fields.length,
|
|
||||||
"The number of values must be equal to the number of fields");
|
|
||||||
|
|
||||||
T instance;
|
|
||||||
try {
|
|
||||||
instance = defaultConstructor.newInstance();
|
|
||||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new UnsupportedOperationException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < fields.length; ++i) {
|
|
||||||
try {
|
|
||||||
Preconditions.checkNotNull(values[i]);
|
|
||||||
fields[i].set(instance, values[i]);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new UnsupportedOperationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a provider for a {@code FieldInjection<T>} instance, i.e. a provides an object
|
|
||||||
* with which field injection can be performed on the given class if applicable. The provided
|
|
||||||
* value is {@code null} if field injection cannot be applied to the class.
|
|
||||||
*
|
|
||||||
* @param clazz the class to provide field injection for
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return field injection provider for the given class, or null if not applicable
|
|
||||||
*/
|
|
||||||
public static <T> Provider<FieldInjection<T>> provide(final Class<T> clazz) {
|
|
||||||
return new Provider<FieldInjection<T>>() {
|
|
||||||
@Override
|
|
||||||
public FieldInjection<T> get() {
|
|
||||||
Constructor<T> constructor = getDefaultConstructor(clazz);
|
|
||||||
if (constructor == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<Field> fields = getInjectionFields(clazz);
|
|
||||||
return fields.isEmpty() ? null : new FieldInjection<>(constructor, fields);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Field> getInjectionFields(Class<?> clazz) {
|
|
||||||
List<Field> fields = new ArrayList<>();
|
|
||||||
for (Field field : clazz.getDeclaredFields()) {
|
|
||||||
if (field.isAnnotationPresent(Inject.class)) {
|
|
||||||
if (Modifier.isStatic(field.getModifiers())) {
|
|
||||||
throw new IllegalStateException(String.format("Field '%s' in class '%s' is static but "
|
|
||||||
+ "annotated with @Inject", field.getName(), clazz.getSimpleName()));
|
|
||||||
}
|
|
||||||
field.setAccessible(true);
|
|
||||||
fields.add(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Class<?> getFirstNonInjectAnnotation(Field field) {
|
|
||||||
for (Annotation annotation : field.getAnnotations()) {
|
|
||||||
if (annotation.annotationType() != Inject.class) {
|
|
||||||
return annotation.annotationType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) {
|
|
||||||
try {
|
|
||||||
Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
|
|
||||||
defaultConstructor.setAccessible(true);
|
|
||||||
return (Constructor<T>) defaultConstructor;
|
|
||||||
} catch (NoSuchMethodException ignore) {
|
|
||||||
// no default constructor available
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
src/main/java/fr/xephi/authme/initialization/HasCleanup.java
Normal file
14
src/main/java/fr/xephi/authme/initialization/HasCleanup.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common interface for types which have data that becomes outdated
|
||||||
|
* and that can be cleaned up periodically.
|
||||||
|
*/
|
||||||
|
public interface HasCleanup {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the cleanup action.
|
||||||
|
*/
|
||||||
|
void performCleanup();
|
||||||
|
|
||||||
|
}
|
||||||
171
src/main/java/fr/xephi/authme/initialization/Initializer.java
Normal file
171
src/main/java/fr/xephi/authme/initialization/Initializer.java
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
|
import fr.xephi.authme.AuthMe;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.datasource.CacheDataSource;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.datasource.DataSourceType;
|
||||||
|
import fr.xephi.authme.datasource.FlatFile;
|
||||||
|
import fr.xephi.authme.datasource.MySQL;
|
||||||
|
import fr.xephi.authme.datasource.SQLite;
|
||||||
|
import fr.xephi.authme.output.ConsoleFilter;
|
||||||
|
import fr.xephi.authme.output.Log4JFilter;
|
||||||
|
import fr.xephi.authme.output.MessageKey;
|
||||||
|
import fr.xephi.authme.output.Messages;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.SettingsMigrationService;
|
||||||
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
|
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
|
||||||
|
import fr.xephi.authme.settings.propertymap.PropertyMap;
|
||||||
|
import fr.xephi.authme.util.BukkitService;
|
||||||
|
import fr.xephi.authme.util.FileUtils;
|
||||||
|
import fr.xephi.authme.util.MigrationService;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
|
||||||
|
import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes various services.
|
||||||
|
*/
|
||||||
|
public class Initializer {
|
||||||
|
|
||||||
|
private static final String FLATFILE_FILENAME = "auths.db";
|
||||||
|
private static final int SQLITE_MAX_SIZE = 4000;
|
||||||
|
|
||||||
|
private AuthMe authMe;
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
|
public Initializer(AuthMe authMe, BukkitService bukkitService) {
|
||||||
|
this.authMe = authMe;
|
||||||
|
this.bukkitService = bukkitService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the plugin's settings.
|
||||||
|
*
|
||||||
|
* @return The settings instance, or null if it could not be constructed
|
||||||
|
*/
|
||||||
|
public Settings createSettings() throws Exception {
|
||||||
|
File configFile = new File(authMe.getDataFolder(), "config.yml");
|
||||||
|
PropertyMap properties = SettingsFieldRetriever.getAllPropertyFields();
|
||||||
|
SettingsMigrationService migrationService = new SettingsMigrationService();
|
||||||
|
if (FileUtils.copyFileFromResource(configFile, "config.yml")) {
|
||||||
|
return new Settings(configFile, authMe.getDataFolder(), properties, migrationService);
|
||||||
|
}
|
||||||
|
throw new Exception("Could not copy config.yml from JAR to plugin folder");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the data source.
|
||||||
|
*
|
||||||
|
* @param settings the settings
|
||||||
|
* @throws ClassNotFoundException if no driver could be found for the datasource
|
||||||
|
* @throws SQLException when initialization of a SQL datasource failed
|
||||||
|
* @throws IOException if flat file cannot be read
|
||||||
|
*/
|
||||||
|
public DataSource setupDatabase(Settings settings) throws ClassNotFoundException, SQLException, IOException {
|
||||||
|
DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
|
||||||
|
DataSource dataSource;
|
||||||
|
switch (dataSourceType) {
|
||||||
|
case FILE:
|
||||||
|
File source = new File(authMe.getDataFolder(), FLATFILE_FILENAME);
|
||||||
|
dataSource = new FlatFile(source);
|
||||||
|
break;
|
||||||
|
case MYSQL:
|
||||||
|
dataSource = new MySQL(settings);
|
||||||
|
break;
|
||||||
|
case SQLITE:
|
||||||
|
dataSource = new SQLite(settings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSource convertedSource = MigrationService.convertFlatfileToSqlite(settings, dataSource);
|
||||||
|
dataSource = convertedSource == null ? dataSource : convertedSource;
|
||||||
|
|
||||||
|
if (settings.getProperty(DatabaseSettings.USE_CACHING)) {
|
||||||
|
dataSource = new CacheDataSource(dataSource);
|
||||||
|
}
|
||||||
|
if (DataSourceType.SQLITE.equals(dataSourceType)) {
|
||||||
|
checkDataSourceSize(dataSource);
|
||||||
|
}
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDataSourceSize(final DataSource dataSource) {
|
||||||
|
bukkitService.runTaskAsynchronously(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int accounts = dataSource.getAccountsRegistered();
|
||||||
|
if (accounts >= SQLITE_MAX_SIZE) {
|
||||||
|
ConsoleLogger.warning("YOU'RE USING THE SQLITE DATABASE WITH "
|
||||||
|
+ accounts + "+ ACCOUNTS; FOR BETTER PERFORMANCE, PLEASE UPGRADE TO MYSQL!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the console filter if enabled.
|
||||||
|
*
|
||||||
|
* @param settings the settings
|
||||||
|
* @param logger the plugin logger
|
||||||
|
*/
|
||||||
|
public void setupConsoleFilter(Settings settings, Logger logger) {
|
||||||
|
if (!settings.getProperty(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Try to set the log4j filter
|
||||||
|
try {
|
||||||
|
Class.forName("org.apache.logging.log4j.core.filter.AbstractFilter");
|
||||||
|
setLog4JFilter();
|
||||||
|
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||||
|
// log4j is not available
|
||||||
|
ConsoleLogger.info("You're using Minecraft 1.6.x or older, Log4J support will be disabled");
|
||||||
|
ConsoleFilter filter = new ConsoleFilter();
|
||||||
|
logger.setFilter(filter);
|
||||||
|
Bukkit.getLogger().setFilter(filter);
|
||||||
|
Logger.getLogger("Minecraft").setFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the console filter to remove the passwords
|
||||||
|
private static void setLog4JFilter() {
|
||||||
|
org.apache.logging.log4j.core.Logger logger;
|
||||||
|
logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
|
||||||
|
logger.addFilter(new Log4JFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleRecallEmailTask(Settings settings, final DataSource dataSource, final Messages messages) {
|
||||||
|
if (!settings.getProperty(RECALL_PLAYERS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bukkitService.runTaskTimerAsynchronously(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (PlayerAuth auth : dataSource.getLoggedPlayers()) {
|
||||||
|
String email = auth.getEmail();
|
||||||
|
if (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email)) {
|
||||||
|
Player player = bukkitService.getPlayerExact(auth.getRealName());
|
||||||
|
if (player != null) {
|
||||||
|
messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1, TICKS_PER_MINUTE * settings.getProperty(EmailSettings.DELAY_RECALL));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,36 +0,0 @@
|
|||||||
package fr.xephi.authme.initialization;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common interface for all injection methods.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the concerned object
|
|
||||||
*/
|
|
||||||
public interface Injection<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the dependencies that must be provided to instantiate the given item.
|
|
||||||
*
|
|
||||||
* @return list of dependencies
|
|
||||||
* @see #instantiateWith
|
|
||||||
*/
|
|
||||||
Class<?>[] getDependencies();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the annotation on each dependency if available. The indices of this
|
|
||||||
* array correspond to the ones of {@link #getDependencies()}. If no annotation
|
|
||||||
* is available, {@code null} is stored. If multiple annotations are present, only
|
|
||||||
* one is stored (no guarantee on which one).
|
|
||||||
*
|
|
||||||
* @return annotation for each dependency
|
|
||||||
*/
|
|
||||||
Class<?>[] getDependencyAnnotations();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance with the given values as dependencies. The given values
|
|
||||||
* must correspond to {@link #getDependencies()} in size, order and type.
|
|
||||||
*
|
|
||||||
* @param values the values to set for the dependencies
|
|
||||||
* @return resulting object
|
|
||||||
*/
|
|
||||||
T instantiateWith(Object... values);
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
package fr.xephi.authme.initialization;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback instantiation method for classes with an accessible no-args constructor
|
|
||||||
* and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}.
|
|
||||||
*/
|
|
||||||
public class InstantiationFallback<T> implements Injection<T> {
|
|
||||||
|
|
||||||
private final Constructor<T> constructor;
|
|
||||||
|
|
||||||
private InstantiationFallback(Constructor<T> constructor) {
|
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencies() {
|
|
||||||
return new Class<?>[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?>[] getDependencyAnnotations() {
|
|
||||||
return new Class<?>[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T instantiateWith(Object... values) {
|
|
||||||
if (values == null || values.length > 0) {
|
|
||||||
throw new UnsupportedOperationException("Instantiation fallback cannot have parameters");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return constructor.newInstance();
|
|
||||||
} catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
|
|
||||||
throw new UnsupportedOperationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instantiation fallback if the class is applicable.
|
|
||||||
*
|
|
||||||
* @param clazz the class
|
|
||||||
* @param <T> the class' type
|
|
||||||
* @return instantiation fallback provider for the given class, or null if not applicable
|
|
||||||
*/
|
|
||||||
public static <T> Provider<InstantiationFallback<T>> provide(final Class<T> clazz) {
|
|
||||||
return new Provider<InstantiationFallback<T>>() {
|
|
||||||
@Override
|
|
||||||
public InstantiationFallback<T> get() {
|
|
||||||
Constructor<T> noArgsConstructor = getNoArgsConstructor(clazz);
|
|
||||||
// Return fallback only if we have no args constructor and no @Inject annotation anywhere
|
|
||||||
if (noArgsConstructor != null
|
|
||||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredConstructors())
|
|
||||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredFields())
|
|
||||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredMethods())) {
|
|
||||||
return new InstantiationFallback<>(noArgsConstructor);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> Constructor<T> getNoArgsConstructor(Class<T> clazz) {
|
|
||||||
try {
|
|
||||||
// Note ljacqu 20160504: getConstructor(), unlike getDeclaredConstructor(), only considers public members
|
|
||||||
return clazz.getConstructor();
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <A extends AccessibleObject> boolean isInjectionAnnotationPresent(A[] accessibles) {
|
|
||||||
for (A accessible : accessibles) {
|
|
||||||
if (accessible.isAnnotationPresent(Inject.class) || accessible.isAnnotationPresent(PostConstruct.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,7 +2,7 @@ package fr.xephi.authme.initialization;
|
|||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
import org.mcstats.Metrics;
|
import org.mcstats.Metrics;
|
||||||
@ -10,12 +10,12 @@ import org.mcstats.Metrics.Graph;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class MetricsStarter {
|
public class MetricsManager {
|
||||||
|
|
||||||
private MetricsStarter() {
|
private MetricsManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupMetrics(AuthMe plugin, NewSetting settings) {
|
public static void sendMetrics(AuthMe plugin, Settings settings) {
|
||||||
try {
|
try {
|
||||||
final Metrics metrics = new Metrics(plugin);
|
final Metrics metrics = new Metrics(plugin);
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ public class MetricsStarter {
|
|||||||
metrics.start();
|
metrics.start();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Failed to submit the metrics data
|
// Failed to submit the metrics data
|
||||||
ConsoleLogger.logException("Can't start Metrics! The plugin will work anyway...", e);
|
ConsoleLogger.logException("Can't send Metrics data! The plugin will work anyway...", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.cache.backup.PlayerDataStorage;
|
||||||
|
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
|
import fr.xephi.authme.util.BukkitService;
|
||||||
|
import fr.xephi.authme.util.ValidationService;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all players' data when the plugin shuts down.
|
||||||
|
*/
|
||||||
|
public class OnShutdownPlayerSaver {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
@Inject
|
||||||
|
private Settings settings;
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
@Inject
|
||||||
|
private LimboCache limboCache;
|
||||||
|
@Inject
|
||||||
|
private DataSource dataSource;
|
||||||
|
@Inject
|
||||||
|
private PlayerDataStorage playerDataStorage;
|
||||||
|
@Inject
|
||||||
|
private SpawnLoader spawnLoader;
|
||||||
|
@Inject
|
||||||
|
private PluginHooks pluginHooks;
|
||||||
|
@Inject
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
|
OnShutdownPlayerSaver() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the data of all online players.
|
||||||
|
*/
|
||||||
|
public void saveAllPlayers() {
|
||||||
|
for (Player player : bukkitService.getOnlinePlayers()) {
|
||||||
|
savePlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePlayer(Player player) {
|
||||||
|
final String name = player.getName().toLowerCase();
|
||||||
|
if (pluginHooks.isNpc(player) || validationService.isUnrestricted(name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (limboCache.hasPlayerData(name)) {
|
||||||
|
limboCache.restoreData(player);
|
||||||
|
limboCache.removeFromCache(player);
|
||||||
|
} else {
|
||||||
|
saveLoggedinPlayer(player);
|
||||||
|
}
|
||||||
|
playerCache.removePlayer(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveLoggedinPlayer(Player player) {
|
||||||
|
if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
|
||||||
|
Location loc = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||||
|
final PlayerAuth auth = PlayerAuth.builder()
|
||||||
|
.name(player.getName().toLowerCase())
|
||||||
|
.realName(player.getName())
|
||||||
|
.location(loc).build();
|
||||||
|
dataSource.updateQuitLoc(auth);
|
||||||
|
}
|
||||||
|
if (settings.getProperty(RestrictionSettings.TELEPORT_UNAUTHED_TO_SPAWN)
|
||||||
|
&& !settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
|
||||||
|
if (!playerDataStorage.hasData(player)) {
|
||||||
|
playerDataStorage.saveData(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package fr.xephi.authme.initialization;
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for classes that keep a local copy of certain settings.
|
* Interface for classes that keep a local copy of certain settings.
|
||||||
@ -8,9 +8,9 @@ import fr.xephi.authme.settings.NewSetting;
|
|||||||
public interface SettingsDependent {
|
public interface SettingsDependent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the needed settings.
|
* Performs a reload with the provided settings instance.
|
||||||
*
|
*
|
||||||
* @param settings the settings instance
|
* @param settings the settings instance
|
||||||
*/
|
*/
|
||||||
void loadSettings(NewSetting settings);
|
void reload(Settings settings);
|
||||||
}
|
}
|
||||||
|
|||||||
88
src/main/java/fr/xephi/authme/initialization/TaskCloser.java
Normal file
88
src/main/java/fr/xephi/authme/initialization/TaskCloser.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package fr.xephi.authme.initialization;
|
||||||
|
|
||||||
|
import fr.xephi.authme.AuthMe;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
import org.bukkit.scheduler.BukkitWorker;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for asynchronous tasks to complete before closing the data source
|
||||||
|
* so the plugin can shut down properly.
|
||||||
|
*/
|
||||||
|
public class TaskCloser implements Runnable {
|
||||||
|
|
||||||
|
private final BukkitScheduler scheduler;
|
||||||
|
private final Logger logger;
|
||||||
|
private final AuthMe plugin;
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin instance
|
||||||
|
* @param dataSource the data source (nullable)
|
||||||
|
*/
|
||||||
|
public TaskCloser(AuthMe plugin, DataSource dataSource) {
|
||||||
|
this.scheduler = plugin.getServer().getScheduler();
|
||||||
|
this.logger = plugin.getLogger();
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<Integer> pendingTasks = getPendingTasks();
|
||||||
|
logger.log(Level.INFO, "Waiting for {0} tasks to finish", pendingTasks.size());
|
||||||
|
int progress = 0;
|
||||||
|
|
||||||
|
//one minute + some time checking the running state
|
||||||
|
int tries = 60;
|
||||||
|
while (!pendingTasks.isEmpty()) {
|
||||||
|
if (tries <= 0) {
|
||||||
|
logger.log(Level.INFO, "Async tasks times out after to many tries {0}", pendingTasks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<Integer> iterator = pendingTasks.iterator(); iterator.hasNext(); ) {
|
||||||
|
int taskId = iterator.next();
|
||||||
|
if (!scheduler.isCurrentlyRunning(taskId)) {
|
||||||
|
iterator.remove();
|
||||||
|
progress++;
|
||||||
|
logger.log(Level.INFO, "Progress: {0} / {1}", new Object[]{progress, pendingTasks.size()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSource != null) {
|
||||||
|
dataSource.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getPendingTasks() {
|
||||||
|
List<Integer> pendingTasks = new ArrayList<>();
|
||||||
|
//returns only the async tasks
|
||||||
|
for (BukkitWorker pendingTask : scheduler.getActiveWorkers()) {
|
||||||
|
if (pendingTask.getOwner().equals(plugin)
|
||||||
|
//it's not a periodic task
|
||||||
|
&& !scheduler.isQueued(pendingTask.getTaskId())) {
|
||||||
|
pendingTasks.add(pendingTask.getTaskId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pendingTasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,97 +0,0 @@
|
|||||||
package fr.xephi.authme.listener;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.ProtocolManager;
|
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
|
|
||||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
|
||||||
import fr.xephi.authme.util.BukkitService;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class AuthMeTablistPacketAdapter extends PacketAdapter {
|
|
||||||
|
|
||||||
private final BukkitService bukkitService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) {
|
|
||||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
|
|
||||||
this.bukkitService = bukkitService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
|
|
||||||
//this hides the tablist for the new joining players. Already playing users will see the new player
|
|
||||||
try {
|
|
||||||
if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
} catch (FieldAccessException e) {
|
|
||||||
ConsoleLogger.logException("Couldn't access field", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendTablist(Player receiver) {
|
|
||||||
WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(receiver);
|
|
||||||
|
|
||||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
|
||||||
NativeGameMode gamemode = NativeGameMode.fromBukkit(receiver.getGameMode());
|
|
||||||
|
|
||||||
WrappedChatComponent displayName = WrappedChatComponent.fromText(receiver.getDisplayName());
|
|
||||||
PlayerInfoData playerInfoData = new PlayerInfoData(gameProfile, 0, gamemode, displayName);
|
|
||||||
|
|
||||||
//add info containing the skin data
|
|
||||||
PacketContainer addInfo = protocolManager.createPacket(PacketType.Play.Server.PLAYER_INFO);
|
|
||||||
addInfo.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER);
|
|
||||||
addInfo.getPlayerInfoDataLists().write(0, Arrays.asList(playerInfoData));
|
|
||||||
|
|
||||||
try {
|
|
||||||
//adds the skin
|
|
||||||
protocolManager.sendServerPacket(receiver, addInfo);
|
|
||||||
} catch (InvocationTargetException ex) {
|
|
||||||
plugin.getLogger().log(Level.SEVERE, "Exception sending instant skin change packet", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
//triggers an update for others player to see them
|
|
||||||
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
|
|
||||||
if (onlinePlayer.equals(receiver) || !receiver.canSee(onlinePlayer)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//removes the entity and display them
|
|
||||||
receiver.hidePlayer(onlinePlayer);
|
|
||||||
receiver.showPlayer(onlinePlayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register() {
|
|
||||||
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(this);
|
|
||||||
} else {
|
|
||||||
ConsoleLogger.info("The hideTablist feature is not compatible with your minecraft version");
|
|
||||||
ConsoleLogger.info("It requires 1.8+. Disabling the hideTablist feature...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregister() {
|
|
||||||
ProtocolLibrary.getProtocolManager().removePacketListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockPlaceEvent;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class AuthMeBlockListener implements Listener {
|
public class BlockListener implements Listener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ListenerService listenerService;
|
private ListenerService listenerService;
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package fr.xephi.authme.listener;
|
package fr.xephi.authme.listener;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Projectile;
|
import org.bukkit.entity.Projectile;
|
||||||
@ -20,14 +21,14 @@ import javax.inject.Inject;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class AuthMeEntityListener implements Listener {
|
public class EntityListener implements Listener {
|
||||||
|
|
||||||
private final ListenerService listenerService;
|
private final ListenerService listenerService;
|
||||||
private Method getShooter;
|
private Method getShooter;
|
||||||
private boolean shooterIsLivingEntity;
|
private boolean shooterIsLivingEntity;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AuthMeEntityListener(ListenerService listenerService) {
|
EntityListener(ListenerService listenerService) {
|
||||||
this.listenerService = listenerService;
|
this.listenerService = listenerService;
|
||||||
try {
|
try {
|
||||||
getShooter = Projectile.class.getDeclaredMethod("getShooter");
|
getShooter = Projectile.class.getDeclaredMethod("getShooter");
|
||||||
@ -39,7 +40,7 @@ public class AuthMeEntityListener implements Listener {
|
|||||||
|
|
||||||
// Note #360: npc status can be used to bypass security!!!
|
// Note #360: npc status can be used to bypass security!!!
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onEntityDamage(EntityDamageEvent event) {
|
public void onDamage(EntityDamageEvent event) {
|
||||||
if (listenerService.shouldCancelEvent(event)) {
|
if (listenerService.shouldCancelEvent(event)) {
|
||||||
event.getEntity().setFireTicks(0);
|
event.getEntity().setFireTicks(0);
|
||||||
event.setDamage(0);
|
event.setDamage(0);
|
||||||
@ -48,16 +49,16 @@ public class AuthMeEntityListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onEntityTarget(EntityTargetEvent event) {
|
public void onAttack(EntityDamageByEntityEvent event) {
|
||||||
if (listenerService.shouldCancelEvent(event)) {
|
if (listenerService.shouldCancelEvent(event.getDamager())) {
|
||||||
event.setTarget(null);
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onDamage(EntityDamageByEntityEvent event) {
|
public void onEntityTarget(EntityTargetEvent event) {
|
||||||
if (listenerService.shouldCancelEvent(event)) {
|
if (listenerService.shouldCancelEvent(event)) {
|
||||||
|
event.setTarget(null);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,9 +6,9 @@ import fr.xephi.authme.util.StringUtils;
|
|||||||
/**
|
/**
|
||||||
* Exception thrown when a verification has failed.
|
* Exception thrown when a verification has failed.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class FailedVerificationException extends Exception {
|
public class FailedVerificationException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3903242223297960699L;
|
||||||
private final MessageKey reason;
|
private final MessageKey reason;
|
||||||
private final String[] args;
|
private final String[] args;
|
||||||
|
|
||||||
|
|||||||
@ -4,17 +4,15 @@ import fr.xephi.authme.cache.auth.PlayerCache;
|
|||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.hooks.PluginHooks;
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.entity.EntityEvent;
|
import org.bukkit.event.entity.EntityEvent;
|
||||||
import org.bukkit.event.player.PlayerEvent;
|
import org.bukkit.event.player.PlayerEvent;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service class for the AuthMe listeners to determine whether an event should be canceled.
|
* Service class for the AuthMe listeners to determine whether an event should be canceled.
|
||||||
@ -24,16 +22,18 @@ class ListenerService implements SettingsDependent {
|
|||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final PluginHooks pluginHooks;
|
private final PluginHooks pluginHooks;
|
||||||
private final PlayerCache playerCache;
|
private final PlayerCache playerCache;
|
||||||
|
private final ValidationService validationService;
|
||||||
|
|
||||||
private boolean isRegistrationForced;
|
private boolean isRegistrationForced;
|
||||||
private Set<String> unrestrictedNames;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ListenerService(NewSetting settings, DataSource dataSource, PluginHooks pluginHooks, PlayerCache playerCache) {
|
ListenerService(Settings settings, DataSource dataSource, PluginHooks pluginHooks,
|
||||||
|
PlayerCache playerCache, ValidationService validationService) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.pluginHooks = pluginHooks;
|
this.pluginHooks = pluginHooks;
|
||||||
this.playerCache = playerCache;
|
this.playerCache = playerCache;
|
||||||
loadSettings(settings);
|
this.validationService = validationService;
|
||||||
|
reload(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,10 +44,19 @@ class ListenerService implements SettingsDependent {
|
|||||||
*/
|
*/
|
||||||
public boolean shouldCancelEvent(EntityEvent event) {
|
public boolean shouldCancelEvent(EntityEvent event) {
|
||||||
Entity entity = event.getEntity();
|
Entity entity = event.getEntity();
|
||||||
|
return shouldCancelEvent(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns, based on the entity associated with the event, whether or not the event should be canceled.
|
||||||
|
*
|
||||||
|
* @param entity the player entity to verify
|
||||||
|
* @return true if the associated event should be canceled, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldCancelEvent(Entity entity) {
|
||||||
if (entity == null || !(entity instanceof Player)) {
|
if (entity == null || !(entity instanceof Player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = (Player) entity;
|
Player player = (Player) entity;
|
||||||
return shouldCancelEvent(player);
|
return shouldCancelEvent(player);
|
||||||
}
|
}
|
||||||
@ -74,10 +83,8 @@ class ListenerService implements SettingsDependent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSettings(NewSetting settings) {
|
public void reload(Settings settings) {
|
||||||
isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE);
|
isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE);
|
||||||
// Keep unrestricted names as Set for more efficient contains()
|
|
||||||
unrestrictedNames = new HashSet<>(settings.getProperty(RestrictionSettings.UNRESTRICTED_NAMES));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +95,7 @@ class ListenerService implements SettingsDependent {
|
|||||||
* @return true if the player may play, false otherwise
|
* @return true if the player may play, false otherwise
|
||||||
*/
|
*/
|
||||||
private boolean checkAuth(String name) {
|
private boolean checkAuth(String name) {
|
||||||
if (isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
if (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
|
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
|
||||||
@ -96,14 +103,4 @@ class ListenerService implements SettingsDependent {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the name is unrestricted according to the configured settings.
|
|
||||||
*
|
|
||||||
* @param name the name to verify
|
|
||||||
* @return true if unrestricted, false otherwise
|
|
||||||
*/
|
|
||||||
private boolean isUnrestricted(String name) {
|
|
||||||
return unrestrictedNames.contains(name.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,13 @@ import fr.xephi.authme.output.MessageKey;
|
|||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import fr.xephi.authme.util.Utils;
|
||||||
import fr.xephi.authme.util.ValidationService;
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -31,7 +32,7 @@ import java.util.regex.Pattern;
|
|||||||
class OnJoinVerifier implements Reloadable {
|
class OnJoinVerifier implements Reloadable {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private NewSetting settings;
|
private Settings settings;
|
||||||
@Inject
|
@Inject
|
||||||
private DataSource dataSource;
|
private DataSource dataSource;
|
||||||
@Inject
|
@Inject
|
||||||
@ -56,13 +57,7 @@ class OnJoinVerifier implements Reloadable {
|
|||||||
@Override
|
@Override
|
||||||
public void reload() {
|
public void reload() {
|
||||||
String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS);
|
String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS);
|
||||||
try {
|
nicknamePattern = Utils.safePatternCompile(nickRegEx);
|
||||||
nicknamePattern = Pattern.compile(nickRegEx);
|
|
||||||
} catch (Exception e) {
|
|
||||||
nicknamePattern = Pattern.compile(".*?");
|
|
||||||
ConsoleLogger.showError("Nickname pattern is not a valid regular expression! "
|
|
||||||
+ "Fallback to allowing all nicknames");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +68,7 @@ class OnJoinVerifier implements Reloadable {
|
|||||||
*/
|
*/
|
||||||
public void checkAntibot(String playerName, boolean isAuthAvailable) throws FailedVerificationException {
|
public void checkAntibot(String playerName, boolean isAuthAvailable) throws FailedVerificationException {
|
||||||
if (antiBot.getAntiBotStatus() == AntiBot.AntiBotStatus.ACTIVE && !isAuthAvailable) {
|
if (antiBot.getAntiBotStatus() == AntiBot.AntiBotStatus.ACTIVE && !isAuthAvailable) {
|
||||||
antiBot.antibotKicked.addIfAbsent(playerName);
|
antiBot.addPlayerKick(playerName);
|
||||||
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
|
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,15 +157,15 @@ class OnJoinVerifier implements Reloadable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that the player's country is admitted if he is not registered.
|
* Checks that the player's country is admitted.
|
||||||
*
|
*
|
||||||
* @param isAuthAvailable whether or not the user is registered
|
* @param isAuthAvailable whether or not the user is registered
|
||||||
* @param event the login event of the player
|
* @param playerIp the ip address of the player
|
||||||
*/
|
*/
|
||||||
public void checkPlayerCountry(boolean isAuthAvailable,
|
public void checkPlayerCountry(boolean isAuthAvailable,
|
||||||
PlayerLoginEvent event) throws FailedVerificationException {
|
String playerIp) throws FailedVerificationException {
|
||||||
if (!isAuthAvailable && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
|
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
|
||||||
String playerIp = event.getAddress().getHostAddress();
|
&& settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
|
||||||
if (!validationService.isCountryAdmitted(playerIp)) {
|
if (!validationService.isCountryAdmitted(playerIp)) {
|
||||||
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
|
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,13 +6,14 @@ import fr.xephi.authme.datasource.DataSource;
|
|||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
import fr.xephi.authme.output.Messages;
|
import fr.xephi.authme.output.Messages;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.TeleportationService;
|
||||||
|
import fr.xephi.authme.util.ValidationService;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -23,7 +24,6 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
|
||||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||||
@ -51,12 +51,12 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAU
|
|||||||
/**
|
/**
|
||||||
* Listener class for player events.
|
* Listener class for player events.
|
||||||
*/
|
*/
|
||||||
public class AuthMePlayerListener implements Listener {
|
public class PlayerListener implements Listener {
|
||||||
|
|
||||||
public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>();
|
public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private NewSetting settings;
|
private Settings settings;
|
||||||
@Inject
|
@Inject
|
||||||
private Messages m;
|
private Messages m;
|
||||||
@Inject
|
@Inject
|
||||||
@ -73,6 +73,10 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
private OnJoinVerifier onJoinVerifier;
|
private OnJoinVerifier onJoinVerifier;
|
||||||
@Inject
|
@Inject
|
||||||
private ListenerService listenerService;
|
private ListenerService listenerService;
|
||||||
|
@Inject
|
||||||
|
private TeleportationService teleportationService;
|
||||||
|
@Inject
|
||||||
|
private ValidationService validationService;
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||||
@ -141,10 +145,6 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
|
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
|
||||||
// "cancel" the event
|
// "cancel" the event
|
||||||
event.setTo(event.getFrom());
|
event.setTo(event.getFrom());
|
||||||
if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
|
||||||
player.setFlySpeed(0.0f);
|
|
||||||
player.setWalkSpeed(0.0f);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,47 +189,24 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOW)
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
if (player != null) {
|
teleportationService.teleportNewPlayerToFirstSpawn(player);
|
||||||
// Schedule login task so works after the prelogin
|
management.performJoin(player);
|
||||||
// (Fix found by Koolaid5000)
|
|
||||||
bukkitService.runTask(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
management.performJoin(player);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note ljacqu 20160528: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
|
// Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
|
||||||
// e.g. CraftBukkit does not. So we need to run crucial things in onPlayerLogin, too
|
// e.g. CraftBukkit does not fire it. So we need to run crucial things with PlayerLoginEvent.
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
// Single session feature can be implemented for Spigot and CraftBukkit by canceling a kick
|
||||||
public void onPreLogin(AsyncPlayerPreLoginEvent event) {
|
// event caused by "logged in from another location". The nicer way, but only for Spigot, would be
|
||||||
final String name = event.getName().toLowerCase();
|
// to check in the AsyncPlayerPreLoginEvent. To support all servers, we use the less nice way.
|
||||||
final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName());
|
|
||||||
|
|
||||||
try {
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
// Potential performance improvement: make checkAntiBot not require `isAuthAvailable` info and use
|
|
||||||
// "checkKickNonRegistered" as last -> no need to query the DB before checking antibot / name
|
|
||||||
onJoinVerifier.checkAntibot(name, isAuthAvailable);
|
|
||||||
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
|
|
||||||
onJoinVerifier.checkIsValidName(name);
|
|
||||||
// Note #760: Single session must be checked here - checking with PlayerLoginEvent is too late and
|
|
||||||
// the first connection will have been kicked. This means this feature doesn't work on CraftBukkit.
|
|
||||||
onJoinVerifier.checkSingleSession(name);
|
|
||||||
} catch (FailedVerificationException e) {
|
|
||||||
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
|
|
||||||
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
|
||||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
if (Utils.isUnrestricted(player)) {
|
final String name = player.getName();
|
||||||
|
if (validationService.isUnrestricted(name)) {
|
||||||
return;
|
return;
|
||||||
} else if (onJoinVerifier.refusePlayerForFullServer(event)) {
|
} else if (onJoinVerifier.refusePlayerForFullServer(event)) {
|
||||||
return;
|
return;
|
||||||
@ -237,16 +214,20 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String name = player.getName().toLowerCase();
|
|
||||||
final PlayerAuth auth = dataSource.getAuth(player.getName());
|
|
||||||
final boolean isAuthAvailable = (auth != null);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
onJoinVerifier.checkAntibot(name, isAuthAvailable);
|
// Fast stuff
|
||||||
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
|
onJoinVerifier.checkSingleSession(name);
|
||||||
onJoinVerifier.checkIsValidName(name);
|
onJoinVerifier.checkIsValidName(name);
|
||||||
|
|
||||||
|
// Get the auth later as this may cause the single session check to fail
|
||||||
|
// Slow stuff
|
||||||
|
final PlayerAuth auth = dataSource.getAuth(name);
|
||||||
|
final boolean isAuthAvailable = (auth != null);
|
||||||
|
final String lowerName = name.toLowerCase();
|
||||||
|
onJoinVerifier.checkAntibot(lowerName, isAuthAvailable);
|
||||||
|
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
|
||||||
onJoinVerifier.checkNameCasing(player, auth);
|
onJoinVerifier.checkNameCasing(player, auth);
|
||||||
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event);
|
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress());
|
||||||
} catch (FailedVerificationException e) {
|
} catch (FailedVerificationException e) {
|
||||||
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
|
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
|
||||||
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
|
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
|
||||||
@ -254,6 +235,7 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
antiBot.handlePlayerJoin(player);
|
antiBot.handlePlayerJoin(player);
|
||||||
|
teleportationService.teleportOnJoin(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
@ -262,21 +244,32 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
|
|
||||||
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
|
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
|
||||||
event.setQuitMessage(null);
|
event.setQuitMessage(null);
|
||||||
|
} else if (settings.getProperty(RegistrationSettings.REMOVE_UNLOGGED_LEAVE_MESSAGE)) {
|
||||||
|
if(listenerService.shouldCancelEvent(event)) {
|
||||||
|
event.setQuitMessage(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (antiBot.antibotKicked.contains(player.getName())) {
|
if (antiBot.wasPlayerKicked(player.getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
management.performQuit(player, false);
|
management.performQuit(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||||
public void onPlayerKick(PlayerKickEvent event) {
|
public void onPlayerKick(PlayerKickEvent event) {
|
||||||
Player player = event.getPlayer();
|
// Note #831: Especially for offline CraftBukkit, we need to catch players being kicked because of
|
||||||
|
// "logged in from another location" and to cancel their kick
|
||||||
|
if (settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)
|
||||||
|
&& event.getReason().contains("You logged in from another location")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!antiBot.antibotKicked.contains(player.getName())) {
|
final Player player = event.getPlayer();
|
||||||
management.performQuit(player, true);
|
if (!antiBot.wasPlayerKicked(player.getName())) {
|
||||||
|
management.performQuit(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ import javax.inject.Inject;
|
|||||||
/**
|
/**
|
||||||
* Listener of player events for events introduced in Minecraft 1.6.
|
* Listener of player events for events introduced in Minecraft 1.6.
|
||||||
*/
|
*/
|
||||||
public class AuthMePlayerListener16 implements Listener {
|
public class PlayerListener16 implements Listener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ListenerService listenerService;
|
private ListenerService listenerService;
|
||||||
@ -10,7 +10,7 @@ import javax.inject.Inject;
|
|||||||
/**
|
/**
|
||||||
* Listener of player events for events introduced in Minecraft 1.8.
|
* Listener of player events for events introduced in Minecraft 1.8.
|
||||||
*/
|
*/
|
||||||
public class AuthMePlayerListener18 implements Listener {
|
public class PlayerListener18 implements Listener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ListenerService listenerService;
|
private ListenerService listenerService;
|
||||||
25
src/main/java/fr/xephi/authme/listener/PlayerListener19.java
Normal file
25
src/main/java/fr/xephi/authme/listener/PlayerListener19.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package fr.xephi.authme.listener;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener of player events for events introduced in Minecraft 1.9.
|
||||||
|
*/
|
||||||
|
public class PlayerListener19 implements Listener {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ListenerService listenerService;
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||||
|
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
||||||
|
if (listenerService.shouldCancelEvent(event)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,53 +1,30 @@
|
|||||||
package fr.xephi.authme.listener;
|
package fr.xephi.authme.listener;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.hooks.PluginHooks;
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
|
||||||
import fr.xephi.authme.output.Messages;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
|
||||||
import fr.xephi.authme.settings.SpawnLoader;
|
import fr.xephi.authme.settings.SpawnLoader;
|
||||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
|
||||||
import fr.xephi.authme.util.ValidationService;
|
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.server.PluginDisableEvent;
|
import org.bukkit.event.server.PluginDisableEvent;
|
||||||
import org.bukkit.event.server.PluginEnableEvent;
|
import org.bukkit.event.server.PluginEnableEvent;
|
||||||
import org.bukkit.event.server.ServerListPingEvent;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class AuthMeServerListener implements Listener {
|
public class ServerListener implements Listener {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private AuthMe plugin;
|
|
||||||
@Inject
|
|
||||||
private Messages messages;
|
|
||||||
@Inject
|
|
||||||
private NewSetting settings;
|
|
||||||
@Inject
|
@Inject
|
||||||
private PluginHooks pluginHooks;
|
private PluginHooks pluginHooks;
|
||||||
@Inject
|
@Inject
|
||||||
private SpawnLoader spawnLoader;
|
private SpawnLoader spawnLoader;
|
||||||
@Inject
|
@Inject
|
||||||
private ValidationService validationService;
|
private ProtocolLibService protocolLibService;
|
||||||
@Inject
|
@Inject
|
||||||
private PermissionsManager permissionsManager;
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
|
||||||
public void onServerPing(ServerListPingEvent event) {
|
|
||||||
if (settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
|
|
||||||
String playerIp = event.getAddress().getHostAddress();
|
|
||||||
if (!validationService.isCountryAdmitted(playerIp)) {
|
|
||||||
event.setMotd(messages.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onPluginDisable(PluginDisableEvent event) {
|
public void onPluginDisable(PluginDisableEvent event) {
|
||||||
// Make sure the plugin instance isn't null
|
// Make sure the plugin instance isn't null
|
||||||
@ -72,13 +49,9 @@ public class AuthMeServerListener implements Listener {
|
|||||||
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
||||||
spawnLoader.unloadEssentialsSpawn();
|
spawnLoader.unloadEssentialsSpawn();
|
||||||
ConsoleLogger.info("EssentialsSpawn has been disabled: unhooking");
|
ConsoleLogger.info("EssentialsSpawn has been disabled: unhooking");
|
||||||
}
|
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
|
||||||
|
protocolLibService.disable();
|
||||||
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
|
ConsoleLogger.warning("ProtocolLib has been disabled, unhooking packet adapters!");
|
||||||
plugin.inventoryProtector = null;
|
|
||||||
plugin.tablistHider = null;
|
|
||||||
plugin.tabComplete = null;
|
|
||||||
ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +75,8 @@ public class AuthMeServerListener implements Listener {
|
|||||||
pluginHooks.tryHookToCombatPlus();
|
pluginHooks.tryHookToCombatPlus();
|
||||||
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
||||||
spawnLoader.loadEssentialsSpawn();
|
spawnLoader.loadEssentialsSpawn();
|
||||||
}
|
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
|
||||||
|
protocolLibService.setup();
|
||||||
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
|
|
||||||
plugin.checkProtocolLib();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package fr.xephi.authme.listener;
|
package fr.xephi.authme.listener.protocollib;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
@ -22,24 +22,16 @@ import com.comphenix.protocol.ProtocolManager;
|
|||||||
import com.comphenix.protocol.events.PacketAdapter;
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
import fr.xephi.authme.settings.Settings;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.apache.commons.lang.reflect.MethodUtils;
|
class InventoryPacketAdapter extends PacketAdapter {
|
||||||
|
|
||||||
public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
|
||||||
|
|
||||||
private static final int PLAYER_INVENTORY = 0;
|
private static final int PLAYER_INVENTORY = 0;
|
||||||
// http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 hotbar, 45 off hand)
|
// http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 hotbar, 45 off hand)
|
||||||
@ -48,12 +40,8 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
|||||||
private static final int ARMOR_SIZE = 4;
|
private static final int ARMOR_SIZE = 4;
|
||||||
private static final int MAIN_SIZE = 27;
|
private static final int MAIN_SIZE = 27;
|
||||||
private static final int HOTBAR_SIZE = 9;
|
private static final int HOTBAR_SIZE = 9;
|
||||||
private static final int OFF_HAND_POSITION = 45;
|
|
||||||
|
|
||||||
private final boolean offHandSupported = MethodUtils
|
public InventoryPacketAdapter(AuthMe plugin) {
|
||||||
.getAccessibleMethod(PlayerInventory.class, "getItemInOffHand", new Class[]{}) != null;
|
|
||||||
|
|
||||||
public AuthMeInventoryPacketAdapter(AuthMe plugin) {
|
|
||||||
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
|
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +51,7 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
|||||||
PacketContainer packet = packetEvent.getPacket();
|
PacketContainer packet = packetEvent.getPacket();
|
||||||
|
|
||||||
byte windowId = packet.getIntegers().read(0).byteValue();
|
byte windowId = packet.getIntegers().read(0).byteValue();
|
||||||
if (windowId == PLAYER_INVENTORY && Settings.protectInventoryBeforeLogInEnabled
|
if (windowId == PLAYER_INVENTORY && !PlayerCache.getInstance().isAuthenticated(player.getName())) {
|
||||||
&& !PlayerCache.getInstance().isAuthenticated(player.getName())) {
|
|
||||||
packetEvent.setCancelled(true);
|
packetEvent.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,52 +64,6 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
|||||||
ProtocolLibrary.getProtocolManager().removePacketListener(this);
|
ProtocolLibrary.getProtocolManager().removePacketListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendInventoryPacket(Player player) {
|
|
||||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
|
||||||
PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
|
|
||||||
|
|
||||||
// we are sending our own inventory
|
|
||||||
inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY);
|
|
||||||
|
|
||||||
ItemStack[] playerCrafting = new ItemStack[CRAFTING_SIZE];
|
|
||||||
Arrays.fill(playerCrafting, new ItemStack(Material.AIR));
|
|
||||||
ItemStack[] armorContents = player.getInventory().getArmorContents();
|
|
||||||
ItemStack[] mainInventory = player.getInventory().getContents();
|
|
||||||
|
|
||||||
// bukkit saves the armor in reversed order
|
|
||||||
Collections.reverse(Arrays.asList(armorContents));
|
|
||||||
|
|
||||||
// same main inventory. The hotbar is at the beginning but it should be at the end of the array
|
|
||||||
ItemStack[] hotbar = Arrays.copyOfRange(mainInventory, 0, HOTBAR_SIZE);
|
|
||||||
ItemStack[] storedInventory = Arrays.copyOfRange(mainInventory, HOTBAR_SIZE, mainInventory.length);
|
|
||||||
|
|
||||||
// concat all parts of the inventory together
|
|
||||||
int inventorySize = CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE + HOTBAR_SIZE;
|
|
||||||
if (offHandSupported) {
|
|
||||||
inventorySize++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack[] completeInventory = new ItemStack[inventorySize];
|
|
||||||
|
|
||||||
System.arraycopy(playerCrafting, 0, completeInventory, 0, CRAFTING_SIZE);
|
|
||||||
System.arraycopy(armorContents, 0, completeInventory, CRAFTING_SIZE, ARMOR_SIZE);
|
|
||||||
|
|
||||||
// storedInventory and hotbar
|
|
||||||
System.arraycopy(storedInventory, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE, MAIN_SIZE);
|
|
||||||
System.arraycopy(hotbar, 0, completeInventory, CRAFTING_SIZE + ARMOR_SIZE + MAIN_SIZE, HOTBAR_SIZE);
|
|
||||||
|
|
||||||
if (offHandSupported) {
|
|
||||||
completeInventory[OFF_HAND_POSITION] = player.getInventory().getItemInOffHand();
|
|
||||||
}
|
|
||||||
|
|
||||||
inventoryPacket.getItemArrayModifier().write(0, completeInventory);
|
|
||||||
try {
|
|
||||||
protocolManager.sendServerPacket(player, inventoryPacket, false);
|
|
||||||
} catch (InvocationTargetException invocationExc) {
|
|
||||||
plugin.getLogger().log(Level.WARNING, "Error during inventory recovery", invocationExc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendBlankInventoryPacket(Player player) {
|
public void sendBlankInventoryPacket(Player player) {
|
||||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||||
PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
|
PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
package fr.xephi.authme.listener.protocollib;
|
||||||
|
|
||||||
|
import ch.jalu.injector.annotations.NoFieldScan;
|
||||||
|
import fr.xephi.authme.AuthMe;
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
|
import fr.xephi.authme.util.BukkitService;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@NoFieldScan
|
||||||
|
public class ProtocolLibService implements SettingsDependent {
|
||||||
|
|
||||||
|
/* Packet Adapters */
|
||||||
|
private InventoryPacketAdapter inventoryPacketAdapter;
|
||||||
|
private TabCompletePacketAdapter tabCompletePacketAdapter;
|
||||||
|
|
||||||
|
/* Settings */
|
||||||
|
private boolean protectInvBeforeLogin;
|
||||||
|
private boolean denyTabCompleteBeforeLogin;
|
||||||
|
|
||||||
|
/* Service */
|
||||||
|
private boolean isEnabled;
|
||||||
|
private AuthMe plugin;
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
private PlayerCache playerCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ProtocolLibService(AuthMe plugin, Settings settings, BukkitService bukkitService, PlayerCache playerCache) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.bukkitService = bukkitService;
|
||||||
|
this.playerCache = playerCache;
|
||||||
|
reload(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the ProtocolLib packet adapters.
|
||||||
|
*/
|
||||||
|
public void setup() {
|
||||||
|
// Check if ProtocolLib is enabled on the server.
|
||||||
|
if (!plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
|
||||||
|
if (protectInvBeforeLogin) {
|
||||||
|
ConsoleLogger.warning("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (denyTabCompleteBeforeLogin) {
|
||||||
|
ConsoleLogger.warning("WARNING! The denyTabComplete feature requires ProtocolLib! Disabling it...");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up packet adapters
|
||||||
|
if (protectInvBeforeLogin && inventoryPacketAdapter == null) {
|
||||||
|
inventoryPacketAdapter = new InventoryPacketAdapter(plugin);
|
||||||
|
inventoryPacketAdapter.register();
|
||||||
|
} else if (inventoryPacketAdapter != null) {
|
||||||
|
inventoryPacketAdapter.unregister();
|
||||||
|
inventoryPacketAdapter = null;
|
||||||
|
}
|
||||||
|
if (denyTabCompleteBeforeLogin && tabCompletePacketAdapter == null) {
|
||||||
|
tabCompletePacketAdapter = new TabCompletePacketAdapter(plugin);
|
||||||
|
tabCompletePacketAdapter.register();
|
||||||
|
} else if (tabCompletePacketAdapter != null) {
|
||||||
|
tabCompletePacketAdapter.unregister();
|
||||||
|
tabCompletePacketAdapter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
isEnabled = false;
|
||||||
|
|
||||||
|
if (inventoryPacketAdapter != null) {
|
||||||
|
inventoryPacketAdapter.unregister();
|
||||||
|
inventoryPacketAdapter = null;
|
||||||
|
}
|
||||||
|
if (tabCompletePacketAdapter != null) {
|
||||||
|
tabCompletePacketAdapter.unregister();
|
||||||
|
tabCompletePacketAdapter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a packet to the player to give them a blank inventory.
|
||||||
|
*
|
||||||
|
* @param player The player to send the packet to.
|
||||||
|
*/
|
||||||
|
public void sendBlankInventoryPacket(Player player) {
|
||||||
|
if (isEnabled && inventoryPacketAdapter != null) {
|
||||||
|
inventoryPacketAdapter.sendBlankInventoryPacket(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload(Settings settings) {
|
||||||
|
boolean oldProtectInventory = this.protectInvBeforeLogin;
|
||||||
|
|
||||||
|
this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
|
||||||
|
this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
|
||||||
|
|
||||||
|
//it was true and will be deactivated now, so we need to restore the inventory for every player
|
||||||
|
if (oldProtectInventory && !protectInvBeforeLogin) {
|
||||||
|
inventoryPacketAdapter.unregister();
|
||||||
|
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
|
||||||
|
if (!playerCache.isAuthenticated(onlinePlayer.getName())) {
|
||||||
|
onlinePlayer.updateInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package fr.xephi.authme.listener;
|
package fr.xephi.authme.listener.protocollib;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
@ -6,17 +6,13 @@ import com.comphenix.protocol.events.ListenerPriority;
|
|||||||
import com.comphenix.protocol.events.PacketAdapter;
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
class TabCompletePacketAdapter extends PacketAdapter {
|
||||||
|
|
||||||
public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
|
public TabCompletePacketAdapter(AuthMe plugin) {
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
|
|
||||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +24,7 @@ public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
} catch (FieldAccessException e) {
|
} catch (FieldAccessException e) {
|
||||||
ConsoleLogger.showError("Couldn't access field.");
|
ConsoleLogger.warning("Couldn't access field.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,47 +3,74 @@ package fr.xephi.authme.mail;
|
|||||||
import fr.xephi.authme.AuthMe;
|
import fr.xephi.authme.AuthMe;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||||
|
import fr.xephi.authme.util.BukkitService;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import org.apache.commons.mail.EmailConstants;
|
import org.apache.commons.mail.EmailConstants;
|
||||||
import org.apache.commons.mail.EmailException;
|
import org.apache.commons.mail.EmailException;
|
||||||
import org.apache.commons.mail.HtmlEmail;
|
import org.apache.commons.mail.HtmlEmail;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import javax.activation.DataSource;
|
||||||
import javax.activation.FileDataSource;
|
import javax.activation.FileDataSource;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
|
||||||
|
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Xephi59
|
* @author Xephi59
|
||||||
*/
|
*/
|
||||||
public class SendMailSSL {
|
public class SendMailSSL {
|
||||||
|
|
||||||
private final AuthMe plugin;
|
@Inject
|
||||||
private final NewSetting settings;
|
private AuthMe plugin;
|
||||||
|
@Inject
|
||||||
|
private Settings settings;
|
||||||
|
@Inject
|
||||||
|
private BukkitService bukkitService;
|
||||||
|
|
||||||
public SendMailSSL(AuthMe plugin, NewSetting settings) {
|
SendMailSSL() {
|
||||||
this.plugin = plugin;
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void main(final PlayerAuth auth, final String newPass) {
|
/**
|
||||||
final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass);
|
* Returns whether all necessary settings are set for sending mails.
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
*
|
||||||
|
* @return true if the necessary email settings are set, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasAllInformation() {
|
||||||
|
return !settings.getProperty(MAIL_ACCOUNT).isEmpty()
|
||||||
|
&& !settings.getProperty(MAIL_PASSWORD).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an email to the user with his new password.
|
||||||
|
*
|
||||||
|
* @param auth the player auth of the player
|
||||||
|
* @param newPass the new password
|
||||||
|
*/
|
||||||
|
public void sendPasswordMail(final PlayerAuth auth, final String newPass) {
|
||||||
|
if (!hasAllInformation()) {
|
||||||
|
ConsoleLogger.warning("Cannot perform email registration: not all email settings are complete");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String mailText = replaceMailTags(settings.getEmailMessage(), auth, newPass);
|
||||||
|
bukkitService.runTaskAsynchronously(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||||
HtmlEmail email;
|
HtmlEmail email;
|
||||||
try {
|
try {
|
||||||
email = initializeMail(auth, settings);
|
email = initializeMail(auth.getEmail());
|
||||||
} catch (EmailException e) {
|
} catch (EmailException e) {
|
||||||
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
||||||
return;
|
return;
|
||||||
@ -54,7 +81,7 @@ public class SendMailSSL {
|
|||||||
File file = null;
|
File file = null;
|
||||||
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
|
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
|
||||||
try {
|
try {
|
||||||
file = generateImage(auth, plugin, newPass);
|
file = generateImage(auth.getNickname(), plugin, newPass);
|
||||||
content = embedImageIntoEmailContent(file, email, content);
|
content = embedImageIntoEmailContent(file, email, content);
|
||||||
} catch (IOException | EmailException e) {
|
} catch (IOException | EmailException e) {
|
||||||
ConsoleLogger.logException(
|
ConsoleLogger.logException(
|
||||||
@ -67,13 +94,12 @@ public class SendMailSSL {
|
|||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File generateImage(PlayerAuth auth, AuthMe plugin, String newPass) throws IOException {
|
private static File generateImage(String name, AuthMe plugin, String newPass) throws IOException {
|
||||||
ImageGenerator gen = new ImageGenerator(newPass);
|
ImageGenerator gen = new ImageGenerator(newPass);
|
||||||
File file = new File(plugin.getDataFolder(), auth.getNickname() + "_new_pass.jpg");
|
File file = new File(plugin.getDataFolder(), name + "_new_pass.jpg");
|
||||||
ImageIO.write(gen.generateImage(), "jpg", file);
|
ImageIO.write(gen.generateImage(), "jpg", file);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -85,8 +111,7 @@ public class SendMailSSL {
|
|||||||
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings)
|
private HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
||||||
throws EmailException {
|
|
||||||
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
|
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
|
||||||
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
|
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
|
||||||
? senderMail
|
? senderMail
|
||||||
@ -98,12 +123,12 @@ public class SendMailSSL {
|
|||||||
email.setCharset(EmailConstants.UTF_8);
|
email.setCharset(EmailConstants.UTF_8);
|
||||||
email.setSmtpPort(port);
|
email.setSmtpPort(port);
|
||||||
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
|
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
|
||||||
email.addTo(auth.getEmail());
|
email.addTo(emailAddress);
|
||||||
email.setFrom(senderMail, senderName);
|
email.setFrom(senderMail, senderName);
|
||||||
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
||||||
email.setAuthentication(senderMail, mailPassword);
|
email.setAuthentication(senderMail, mailPassword);
|
||||||
|
|
||||||
setPropertiesForPort(email, port, settings);
|
setPropertiesForPort(email, port);
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,15 +149,14 @@ public class SendMailSSL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) {
|
private String replaceMailTags(String mailText, PlayerAuth auth, String newPass) {
|
||||||
return mailText
|
return mailText
|
||||||
.replace("<playername />", auth.getNickname())
|
.replace("<playername />", auth.getNickname())
|
||||||
.replace("<servername />", plugin.getServer().getServerName())
|
.replace("<servername />", plugin.getServer().getServerName())
|
||||||
.replace("<generatedpass />", newPass);
|
.replace("<generatedpass />", newPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings)
|
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
|
||||||
throws EmailException {
|
|
||||||
switch (port) {
|
switch (port) {
|
||||||
case 587:
|
case 587:
|
||||||
String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN);
|
String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN);
|
||||||
|
|||||||
@ -2,9 +2,9 @@ package fr.xephi.authme.output;
|
|||||||
|
|
||||||
import org.apache.logging.log4j.Level;
|
import org.apache.logging.log4j.Level;
|
||||||
import org.apache.logging.log4j.Marker;
|
import org.apache.logging.log4j.Marker;
|
||||||
import org.apache.logging.log4j.core.Filter;
|
|
||||||
import org.apache.logging.log4j.core.LogEvent;
|
import org.apache.logging.log4j.core.LogEvent;
|
||||||
import org.apache.logging.log4j.core.Logger;
|
import org.apache.logging.log4j.core.Logger;
|
||||||
|
import org.apache.logging.log4j.core.filter.AbstractFilter;
|
||||||
import org.apache.logging.log4j.message.Message;
|
import org.apache.logging.log4j.message.Message;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,7 +12,8 @@ import org.apache.logging.log4j.message.Message;
|
|||||||
*
|
*
|
||||||
* @author Xephi59
|
* @author Xephi59
|
||||||
*/
|
*/
|
||||||
public class Log4JFilter implements Filter {
|
@SuppressWarnings("serial")
|
||||||
|
public class Log4JFilter extends AbstractFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -50,42 +51,30 @@ public class Log4JFilter implements Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result filter(LogEvent record) {
|
public Result filter(LogEvent event) {
|
||||||
if (record == null) {
|
Message candidate = null;
|
||||||
return Result.NEUTRAL;
|
if(event != null) {
|
||||||
|
candidate = event.getMessage();
|
||||||
}
|
}
|
||||||
return validateMessage(record.getMessage());
|
return validateMessage(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result filter(Logger arg0, Level arg1, Marker arg2, String message, Object... arg4) {
|
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
|
||||||
if (message == null) {
|
return validateMessage(msg);
|
||||||
return Result.NEUTRAL;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
|
||||||
|
return validateMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
|
||||||
|
String candidate = null;
|
||||||
|
if(msg != null) {
|
||||||
|
candidate = msg.toString();
|
||||||
}
|
}
|
||||||
return validateMessage(message);
|
return validateMessage(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result filter(Logger arg0, Level arg1, Marker arg2, Object message, Throwable arg4) {
|
|
||||||
if (message == null) {
|
|
||||||
return Result.NEUTRAL;
|
|
||||||
}
|
|
||||||
return validateMessage(message.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result filter(Logger arg0, Level arg1, Marker arg2, Message message, Throwable arg4) {
|
|
||||||
return validateMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result getOnMatch() {
|
|
||||||
return Result.NEUTRAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result getOnMismatch() {
|
|
||||||
return Result.NEUTRAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/main/java/fr/xephi/authme/output/LogLevel.java
Normal file
38
src/main/java/fr/xephi/authme/output/LogLevel.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package fr.xephi.authme.output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log level.
|
||||||
|
*/
|
||||||
|
public enum LogLevel {
|
||||||
|
|
||||||
|
/** Info: general messages. */
|
||||||
|
INFO(3),
|
||||||
|
|
||||||
|
/** Fine: more detailed messages that may still be interesting to plugin users. */
|
||||||
|
FINE(2),
|
||||||
|
|
||||||
|
/** Debug: very detailed messages for debugging. */
|
||||||
|
DEBUG(1);
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param value the log level; the higher the number the more "important" the level.
|
||||||
|
* A log level enables its number and all above.
|
||||||
|
*/
|
||||||
|
LogLevel(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the current log level includes the given log level.
|
||||||
|
*
|
||||||
|
* @param level the level to process
|
||||||
|
* @return true if the level is enabled, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean includes(LogLevel level) {
|
||||||
|
return value <= level.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -143,7 +143,11 @@ public enum MessageKey {
|
|||||||
|
|
||||||
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
|
ACCOUNTS_OWNED_SELF("accounts_owned_self", "%count"),
|
||||||
|
|
||||||
ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count");
|
ACCOUNTS_OWNED_OTHER("accounts_owned_other", "%name", "%count"),
|
||||||
|
|
||||||
|
KICK_FOR_ADMIN_REGISTER("kicked_admin_registered"),
|
||||||
|
|
||||||
|
INCOMPLETE_EMAIL_SETTINGS("incomplete_email_settings");
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
private String[] tags;
|
private String[] tags;
|
||||||
|
|||||||
@ -2,13 +2,13 @@ package fr.xephi.authme.output;
|
|||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.initialization.SettingsDependent;
|
import fr.xephi.authme.initialization.SettingsDependent;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@ -18,6 +18,9 @@ import java.io.InputStreamReader;
|
|||||||
*/
|
*/
|
||||||
public class Messages implements SettingsDependent {
|
public class Messages implements SettingsDependent {
|
||||||
|
|
||||||
|
// Custom Authme tag replaced to new line
|
||||||
|
private static final String NEWLINE_TAG = "%nl%";
|
||||||
|
|
||||||
private FileConfiguration configuration;
|
private FileConfiguration configuration;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private final String defaultFile;
|
private final String defaultFile;
|
||||||
@ -26,12 +29,12 @@ public class Messages implements SettingsDependent {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param messageFile The messages file to use
|
* @param settings The settings
|
||||||
* @param defaultFile The file with messages to use as default if missing
|
|
||||||
*/
|
*/
|
||||||
public Messages(File messageFile, String defaultFile) {
|
@Inject
|
||||||
initializeFile(messageFile);
|
Messages(Settings settings) {
|
||||||
this.defaultFile = defaultFile;
|
reload(settings);
|
||||||
|
this.defaultFile = settings.getDefaultMessagesFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,18 +73,12 @@ public class Messages implements SettingsDependent {
|
|||||||
* @return The message split by new lines
|
* @return The message split by new lines
|
||||||
*/
|
*/
|
||||||
public String[] retrieve(MessageKey key) {
|
public String[] retrieve(MessageKey key) {
|
||||||
final String code = key.getKey();
|
String message = retrieveMessage(key);
|
||||||
String message = configuration.getString(code);
|
if (message.isEmpty()) {
|
||||||
|
// Return empty array instead of array with 1 empty string as entry
|
||||||
if (message == null) {
|
|
||||||
ConsoleLogger.showError("Error getting message with key '" + code + "'. "
|
|
||||||
+ "Please verify your config file at '" + fileName + "'");
|
|
||||||
return formatMessage(getDefault(code));
|
|
||||||
}
|
|
||||||
if(message.isEmpty()) {
|
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
return formatMessage(message);
|
return message.split("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,8 +87,16 @@ public class Messages implements SettingsDependent {
|
|||||||
* @param key The message key to retrieve
|
* @param key The message key to retrieve
|
||||||
* @return The message from the file
|
* @return The message from the file
|
||||||
*/
|
*/
|
||||||
public String retrieveSingle(MessageKey key) {
|
private String retrieveMessage(MessageKey key) {
|
||||||
return StringUtils.join("\n", retrieve(key));
|
final String code = key.getKey();
|
||||||
|
String message = configuration.getString(code);
|
||||||
|
|
||||||
|
if (message == null) {
|
||||||
|
ConsoleLogger.warning("Error getting message with key '" + code + "'. "
|
||||||
|
+ "Please verify your config file at '" + fileName + "'");
|
||||||
|
return formatMessage(getDefault(code));
|
||||||
|
}
|
||||||
|
return formatMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,24 +109,21 @@ public class Messages implements SettingsDependent {
|
|||||||
* @return The message from the file with replacements
|
* @return The message from the file with replacements
|
||||||
*/
|
*/
|
||||||
public String retrieveSingle(MessageKey key, String... replacements) {
|
public String retrieveSingle(MessageKey key, String... replacements) {
|
||||||
String message = retrieveSingle(key);
|
String message = retrieveMessage(key);
|
||||||
String[] tags = key.getTags();
|
String[] tags = key.getTags();
|
||||||
if (replacements.length == tags.length) {
|
if (replacements.length == tags.length) {
|
||||||
for (int i = 0; i < tags.length; ++i) {
|
for (int i = 0; i < tags.length; ++i) {
|
||||||
message = message.replace(tags[i], replacements[i]);
|
message = message.replace(tags[i], replacements[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
|
ConsoleLogger.warning("Invalid number of replacements for message key '" + key + "'");
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSettings(NewSetting settings) {
|
public void reload(Settings settings) {
|
||||||
initializeFile(settings.getMessagesFile());
|
File messageFile = settings.getMessagesFile();
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeFile(File messageFile) {
|
|
||||||
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
|
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
|
||||||
this.fileName = messageFile.getName();
|
this.fileName = messageFile.getName();
|
||||||
}
|
}
|
||||||
@ -143,12 +145,9 @@ public class Messages implements SettingsDependent {
|
|||||||
return "Error retrieving message '" + code + "'";
|
return "Error retrieving message '" + code + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] formatMessage(String message) {
|
private static String formatMessage(String message) {
|
||||||
String[] lines = message.split("&n");
|
return ChatColor.translateAlternateColorCodes('&', message)
|
||||||
for (int i = 0; i < lines.length; ++i) {
|
.replace(NEWLINE_TAG, "\n");
|
||||||
lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,12 @@ package fr.xephi.authme.permission;
|
|||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||||
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
import fr.xephi.authme.cache.limbo.PlayerData;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -14,17 +16,21 @@ import java.util.Arrays;
|
|||||||
/**
|
/**
|
||||||
* Changes the permission group according to the auth status of the player and the configuration.
|
* Changes the permission group according to the auth status of the player and the configuration.
|
||||||
*/
|
*/
|
||||||
public class AuthGroupHandler {
|
public class AuthGroupHandler implements Reloadable {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PermissionsManager permissionsManager;
|
private PermissionsManager permissionsManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private NewSetting settings;
|
private Settings settings;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private LimboCache limboCache;
|
private LimboCache limboCache;
|
||||||
|
|
||||||
|
private String unloggedInGroup;
|
||||||
|
private String unregisteredGroup;
|
||||||
|
private String registeredGroup;
|
||||||
|
|
||||||
AuthGroupHandler() { }
|
AuthGroupHandler() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,41 +50,74 @@ public class AuthGroupHandler {
|
|||||||
|
|
||||||
// Make sure group support is available
|
// Make sure group support is available
|
||||||
if (!permissionsManager.hasGroupSupport()) {
|
if (!permissionsManager.hasGroupSupport()) {
|
||||||
ConsoleLogger.showError("The current permissions system doesn't have group support, unable to set group!");
|
ConsoleLogger.warning("The current permissions system doesn't have group support, unable to set group!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (group) {
|
switch (group) {
|
||||||
case UNREGISTERED:
|
case UNREGISTERED:
|
||||||
// Remove the other group type groups, set the current group
|
// Remove the other group type groups, set the current group
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.getRegisteredGroup, Settings.getUnloggedinGroup));
|
permissionsManager.removeGroups(player, Arrays.asList(registeredGroup, unloggedInGroup));
|
||||||
return permissionsManager.addGroup(player, Settings.unRegisteredGroup);
|
return permissionsManager.addGroup(player, unregisteredGroup);
|
||||||
|
|
||||||
case REGISTERED:
|
case REGISTERED:
|
||||||
// Remove the other group type groups, set the current group
|
// Remove the other group type groups, set the current group
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getUnloggedinGroup));
|
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, unloggedInGroup));
|
||||||
return permissionsManager.addGroup(player, Settings.getRegisteredGroup);
|
return permissionsManager.addGroup(player, registeredGroup);
|
||||||
|
|
||||||
case NOT_LOGGED_IN:
|
case NOT_LOGGED_IN:
|
||||||
// Remove the other group type groups, set the current group
|
// Remove the other group type groups, set the current group
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup));
|
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup));
|
||||||
return permissionsManager.addGroup(player, Settings.getUnloggedinGroup);
|
return permissionsManager.addGroup(player, unloggedInGroup);
|
||||||
|
|
||||||
case LOGGED_IN:
|
case LOGGED_IN:
|
||||||
// Get the limbo player data
|
// Get the player data
|
||||||
LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase());
|
PlayerData data = limboCache.getPlayerData(player.getName().toLowerCase());
|
||||||
if (limbo == null)
|
if (data == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the players group
|
// Get the players group
|
||||||
String realGroup = limbo.getGroup();
|
String realGroup = data.getGroup();
|
||||||
|
|
||||||
// Remove the other group types groups, set the real group
|
// Remove the other group types groups, set the real group
|
||||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup, Settings.getUnloggedinGroup));
|
permissionsManager.removeGroups(player,
|
||||||
|
Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup)
|
||||||
|
);
|
||||||
return permissionsManager.addGroup(player, realGroup);
|
return permissionsManager.addGroup(player, realGroup);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: This method requires better explanation.
|
||||||
|
* <p>
|
||||||
|
* Set the normal group of a player.
|
||||||
|
*
|
||||||
|
* @param player The player.
|
||||||
|
* @param group The normal group.
|
||||||
|
*
|
||||||
|
* @return True on success, false on failure.
|
||||||
|
*/
|
||||||
|
public boolean addNormal(Player player, String group) {
|
||||||
|
// Check whether the permissions check is enabled
|
||||||
|
if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old groups
|
||||||
|
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup));
|
||||||
|
|
||||||
|
// Add the normal group, return the result
|
||||||
|
return permissionsManager.addGroup(player, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
unloggedInGroup = settings.getProperty(SecuritySettings.UNLOGGEDIN_GROUP);
|
||||||
|
unregisteredGroup = settings.getProperty(HooksSettings.UNREGISTERED_GROUP);
|
||||||
|
registeredGroup = settings.getProperty(HooksSettings.REGISTERED_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package fr.xephi.authme.permission;
|
package fr.xephi.authme.permission;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.permissions.ServerOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default permission to fall back to if there is no support for permission nodes.
|
* The default permission to fall back to if there is no support for permission nodes.
|
||||||
@ -10,7 +10,7 @@ public enum DefaultPermission {
|
|||||||
/** No one has permission. */
|
/** No one has permission. */
|
||||||
NOT_ALLOWED("No permission") {
|
NOT_ALLOWED("No permission") {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluate(CommandSender sender) {
|
public boolean evaluate(ServerOperator sender) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -18,15 +18,15 @@ public enum DefaultPermission {
|
|||||||
/** Only players with OP status have permission. */
|
/** Only players with OP status have permission. */
|
||||||
OP_ONLY("OP's only") {
|
OP_ONLY("OP's only") {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluate(CommandSender sender) {
|
public boolean evaluate(ServerOperator sender) {
|
||||||
return sender.isOp();
|
return sender != null && sender.isOp();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Everyone is granted permission. */
|
/** Everyone is granted permission. */
|
||||||
ALLOWED("Everyone allowed") {
|
ALLOWED("Everyone allowed") {
|
||||||
@Override
|
@Override
|
||||||
public boolean evaluate(CommandSender sender) {
|
public boolean evaluate(ServerOperator sender) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -48,7 +48,7 @@ public enum DefaultPermission {
|
|||||||
* @param sender the sender to process
|
* @param sender the sender to process
|
||||||
* @return true if the sender has permission, false otherwise
|
* @return true if the sender has permission, false otherwise
|
||||||
*/
|
*/
|
||||||
public abstract boolean evaluate(CommandSender sender);
|
public abstract boolean evaluate(ServerOperator sender);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the textual representation.
|
* Return the textual representation.
|
||||||
|
|||||||
@ -1,25 +1,23 @@
|
|||||||
package fr.xephi.authme.permission;
|
package fr.xephi.authme.permission;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.initialization.Reloadable;
|
||||||
import fr.xephi.authme.permission.handlers.BPermissionsHandler;
|
import fr.xephi.authme.permission.handlers.BPermissionsHandler;
|
||||||
import fr.xephi.authme.permission.handlers.GroupManagerHandler;
|
import fr.xephi.authme.permission.handlers.GroupManagerHandler;
|
||||||
import fr.xephi.authme.permission.handlers.PermissionHandler;
|
import fr.xephi.authme.permission.handlers.PermissionHandler;
|
||||||
|
import fr.xephi.authme.permission.handlers.PermissionHandlerException;
|
||||||
import fr.xephi.authme.permission.handlers.PermissionsBukkitHandler;
|
import fr.xephi.authme.permission.handlers.PermissionsBukkitHandler;
|
||||||
import fr.xephi.authme.permission.handlers.PermissionsExHandler;
|
import fr.xephi.authme.permission.handlers.PermissionsExHandler;
|
||||||
import fr.xephi.authme.permission.handlers.VaultHandler;
|
import fr.xephi.authme.permission.handlers.VaultHandler;
|
||||||
import fr.xephi.authme.permission.handlers.ZPermissionsHandler;
|
import fr.xephi.authme.permission.handlers.ZPermissionsHandler;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
|
||||||
import org.anjocaido.groupmanager.GroupManager;
|
import org.anjocaido.groupmanager.GroupManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
|
||||||
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
|
|
||||||
import ru.tehkode.permissions.bukkit.PermissionsEx;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -38,7 +36,7 @@ import java.util.List;
|
|||||||
* @author Tim Visée, http://timvisee.com
|
* @author Tim Visée, http://timvisee.com
|
||||||
* @version 0.3
|
* @version 0.3
|
||||||
*/
|
*/
|
||||||
public class PermissionsManager {
|
public class PermissionsManager implements Reloadable {
|
||||||
|
|
||||||
private final Server server;
|
private final Server server;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
@ -74,90 +72,17 @@ public class PermissionsManager {
|
|||||||
* Setup and hook into the permissions systems.
|
* Setup and hook into the permissions systems.
|
||||||
*/
|
*/
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void setup() {
|
private void setup() {
|
||||||
// Force-unhook from current hooked permissions systems
|
|
||||||
unhook();
|
|
||||||
|
|
||||||
// Loop through all the available permissions system types
|
// Loop through all the available permissions system types
|
||||||
for (PermissionsSystemType type : PermissionsSystemType.values()) {
|
for (PermissionsSystemType type : PermissionsSystemType.values()) {
|
||||||
// Try to find and hook the current plugin if available, print an error if failed
|
|
||||||
try {
|
try {
|
||||||
// Try to find the plugin for the current permissions system
|
PermissionHandler handler = getPermissionHandler(type);
|
||||||
Plugin plugin = pluginManager.getPlugin(type.getPluginName());
|
if (handler != null) {
|
||||||
|
// Show a success message and return
|
||||||
// Make sure a plugin with this name was found
|
this.handler = handler;
|
||||||
if (plugin == null)
|
ConsoleLogger.info("Hooked into " + type.getName() + "!");
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
// Make sure the plugin is enabled before hooking
|
|
||||||
if (!plugin.isEnabled()) {
|
|
||||||
ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the proper method to hook this plugin
|
|
||||||
switch (type) {
|
|
||||||
case PERMISSIONS_EX:
|
|
||||||
// Get the permissions manager for PermissionsEx and make sure it isn't null
|
|
||||||
if (PermissionsEx.getPermissionManager() == null) {
|
|
||||||
ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
handler = new PermissionsExHandler(PermissionsEx.getPermissionManager());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ESSENTIALS_GROUP_MANAGER:
|
|
||||||
// Set the plugin instance
|
|
||||||
handler = new GroupManagerHandler((GroupManager) plugin);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Z_PERMISSIONS:
|
|
||||||
// Set the zPermissions service and make sure it's valid
|
|
||||||
ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class);
|
|
||||||
if (zPermissionsService == null) {
|
|
||||||
ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
handler = new ZPermissionsHandler(zPermissionsService);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VAULT:
|
|
||||||
// Get the permissions provider service
|
|
||||||
RegisteredServiceProvider<Permission> permissionProvider = this.server.getServicesManager().getRegistration(Permission.class);
|
|
||||||
if (permissionProvider == null) {
|
|
||||||
ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Vault provider and make sure it's valid
|
|
||||||
Permission vaultPerms = permissionProvider.getProvider();
|
|
||||||
if (vaultPerms == null) {
|
|
||||||
ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
handler = new VaultHandler(vaultPerms);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_PERMISSIONS:
|
|
||||||
handler = new BPermissionsHandler();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PERMISSIONS_BUKKIT:
|
|
||||||
handler = new PermissionsBukkitHandler();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a success message
|
|
||||||
ConsoleLogger.info("Hooked into " + type.getName() + "!");
|
|
||||||
|
|
||||||
// Return the used permissions system type
|
|
||||||
return;
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// An error occurred, show a warning message
|
// An error occurred, show a warning message
|
||||||
ConsoleLogger.logException("Error while hooking into " + type.getName(), ex);
|
ConsoleLogger.logException("Error while hooking into " + type.getName(), ex);
|
||||||
@ -168,10 +93,42 @@ public class PermissionsManager {
|
|||||||
ConsoleLogger.info("No supported permissions system found! Permissions are disabled!");
|
ConsoleLogger.info("No supported permissions system found! Permissions are disabled!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PermissionHandler getPermissionHandler(PermissionsSystemType type) throws PermissionHandlerException {
|
||||||
|
// Try to find the plugin for the current permissions system
|
||||||
|
Plugin plugin = pluginManager.getPlugin(type.getPluginName());
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the plugin is enabled before hooking
|
||||||
|
if (!plugin.isEnabled()) {
|
||||||
|
ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PERMISSIONS_EX:
|
||||||
|
return new PermissionsExHandler();
|
||||||
|
case ESSENTIALS_GROUP_MANAGER:
|
||||||
|
return new GroupManagerHandler((GroupManager) plugin);
|
||||||
|
case Z_PERMISSIONS:
|
||||||
|
return new ZPermissionsHandler();
|
||||||
|
case VAULT:
|
||||||
|
return new VaultHandler(server);
|
||||||
|
case B_PERMISSIONS:
|
||||||
|
return new BPermissionsHandler();
|
||||||
|
case PERMISSIONS_BUKKIT:
|
||||||
|
return new PermissionsBukkitHandler();
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unhandled permission type '" + type + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Break the hook with all permission systems.
|
* Break the hook with all permission systems.
|
||||||
*/
|
*/
|
||||||
public void unhook() {
|
private void unhook() {
|
||||||
// Reset the current used permissions system
|
// Reset the current used permissions system
|
||||||
this.handler = null;
|
this.handler = null;
|
||||||
|
|
||||||
@ -182,11 +139,12 @@ public class PermissionsManager {
|
|||||||
/**
|
/**
|
||||||
* Reload the permissions manager, and re-hook all permission plugins.
|
* Reload the permissions manager, and re-hook all permission plugins.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void reload() {
|
public void reload() {
|
||||||
// Unhook all permission plugins
|
// Unhook all permission plugins
|
||||||
unhook();
|
unhook();
|
||||||
|
|
||||||
// Set up the permissions manager again, return the result
|
// Set up the permissions manager again
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +174,15 @@ public class PermissionsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the permissions system that is hooked into.
|
||||||
|
*
|
||||||
|
* @return The permissions system, or null.
|
||||||
|
*/
|
||||||
|
public PermissionsSystemType getPermissionSystem() {
|
||||||
|
return isEnabled() ? handler.getPermissionSystem() : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the command sender has permission for the given permissions node. If no permissions system is used or
|
* Check if the command sender has permission for the given permissions node. If no permissions system is used or
|
||||||
* if the sender is not a player (e.g. console user), the player has to be OP in order to have the permission.
|
* if the sender is not a player (e.g. console user), the player has to be OP in order to have the permission.
|
||||||
@ -240,6 +207,39 @@ public class PermissionsManager {
|
|||||||
return handler.hasPermission(player, permissionNode);
|
return handler.hasPermission(player, permissionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a player has permission for the given permission node. This is for offline player checks. If no permissions
|
||||||
|
* system is used, then the player will not have permission.
|
||||||
|
*
|
||||||
|
* @param player The offline player
|
||||||
|
* @param permissionNode The permission node to verify
|
||||||
|
*
|
||||||
|
* @return true if the player has permission, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasPermissionOffline(OfflinePlayer player, PermissionNode permissionNode) {
|
||||||
|
// Check if the permission node is null
|
||||||
|
if (permissionNode == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return permissionNode.getDefaultPermission().evaluate(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.hasPermissionOffline(player.getName(), permissionNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode permissionNode) {
|
||||||
|
if (permissionNode == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return permissionNode.getDefaultPermission().evaluate(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.hasPermissionOffline(name, permissionNode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the current permissions system has group support.
|
* Check whether the current permissions system has group support.
|
||||||
* If no permissions system is hooked, false will be returned.
|
* If no permissions system is hooked, false will be returned.
|
||||||
|
|||||||
@ -24,7 +24,12 @@ public enum PlayerStatePermission implements PermissionNode {
|
|||||||
/**
|
/**
|
||||||
* Permission to be able to register multiple accounts.
|
* Permission to be able to register multiple accounts.
|
||||||
*/
|
*/
|
||||||
ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY);
|
ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission to bypass the purging process
|
||||||
|
*/
|
||||||
|
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The permission node.
|
* The permission node.
|
||||||
|
|||||||
@ -27,6 +27,11 @@ public class BPermissionsHandler implements PermissionHandler {
|
|||||||
return ApiLayer.hasPermission(player.getWorld().getName(), CalculableType.USER, player.getName(), node.getNode());
|
return ApiLayer.hasPermission(player.getWorld().getName(), CalculableType.USER, player.getName(), node.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
return ApiLayer.hasPermission(null, CalculableType.USER, name, node.getNode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
return ApiLayer.hasGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group);
|
return ApiLayer.hasGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group);
|
||||||
|
|||||||
@ -35,6 +35,17 @@ public class GroupManagerHandler implements PermissionHandler {
|
|||||||
return handler != null && handler.has(player, node.getNode());
|
return handler != null && handler.has(player, node.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissionsByPlayerName(name);
|
||||||
|
if(handler == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> perms = handler.getAllPlayersPermissions(name);
|
||||||
|
return perms.contains(node.getNode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissions(player);
|
final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissions(player);
|
||||||
|
|||||||
@ -38,6 +38,17 @@ public interface PermissionHandler {
|
|||||||
*/
|
*/
|
||||||
boolean hasPermission(Player player, PermissionNode node);
|
boolean hasPermission(Player player, PermissionNode node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a player has permission by their name.
|
||||||
|
* Used to check an offline player's permission.
|
||||||
|
*
|
||||||
|
* @param name The player's name.
|
||||||
|
* @param node The permission node.
|
||||||
|
*
|
||||||
|
* @return True if the player has permission.
|
||||||
|
*/
|
||||||
|
boolean hasPermissionOffline(String name, PermissionNode node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the player is in the specified group.
|
* Check whether the player is in the specified group.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
package fr.xephi.authme.permission.handlers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception during the instantiation of a {@link PermissionHandler}.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class PermissionHandlerException extends Exception {
|
||||||
|
|
||||||
|
public PermissionHandlerException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,11 @@ public class PermissionsBukkitHandler implements PermissionHandler {
|
|||||||
return player.hasPermission(node.getNode());
|
return player.hasPermission(node.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
List<String> groupNames = getGroups(player);
|
List<String> groupNames = getGroups(player);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.permission.handlers;
|
package fr.xephi.authme.permission.handlers;
|
||||||
|
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
|
||||||
import fr.xephi.authme.permission.PermissionNode;
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -15,14 +14,16 @@ public class PermissionsExHandler implements PermissionHandler {
|
|||||||
|
|
||||||
private PermissionManager permissionManager;
|
private PermissionManager permissionManager;
|
||||||
|
|
||||||
public PermissionsExHandler(PermissionManager permissionManager) {
|
public PermissionsExHandler() throws PermissionHandlerException {
|
||||||
this.permissionManager = permissionManager;
|
permissionManager = PermissionsEx.getPermissionManager();
|
||||||
|
if (permissionManager == null) {
|
||||||
|
throw new PermissionHandlerException("Could not get manager of PermissionsEx");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addToGroup(Player player, String group) {
|
public boolean addToGroup(Player player, String group) {
|
||||||
if (!PermissionsEx.getPermissionManager().getGroupNames().contains(group)) {
|
if (!PermissionsEx.getPermissionManager().getGroupNames().contains(group)) {
|
||||||
ConsoleLogger.showError("The plugin tried to set " + player + "'s group to '" + group + "', but it doesn't exist!");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,12 @@ public class PermissionsExHandler implements PermissionHandler {
|
|||||||
return user.has(node.getNode());
|
return user.has(node.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
PermissionUser user = permissionManager.getUser(name);
|
||||||
|
return user.has(node.getNode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
PermissionUser user = permissionManager.getUser(player);
|
PermissionUser user = permissionManager.getUser(player);
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package fr.xephi.authme.permission.handlers;
|
|||||||
import fr.xephi.authme.permission.PermissionNode;
|
import fr.xephi.authme.permission.PermissionNode;
|
||||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
import net.milkbowl.vault.permission.Permission;
|
||||||
|
import org.bukkit.Server;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -12,8 +14,24 @@ public class VaultHandler implements PermissionHandler {
|
|||||||
|
|
||||||
private Permission vaultProvider;
|
private Permission vaultProvider;
|
||||||
|
|
||||||
public VaultHandler(Permission vaultProvider) {
|
public VaultHandler(Server server) throws PermissionHandlerException {
|
||||||
this.vaultProvider = vaultProvider;
|
this.vaultProvider = getVaultPermission(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Permission getVaultPermission(Server server) throws PermissionHandlerException {
|
||||||
|
// Get the permissions provider service
|
||||||
|
RegisteredServiceProvider<Permission> permissionProvider = server
|
||||||
|
.getServicesManager().getRegistration(Permission.class);
|
||||||
|
if (permissionProvider == null) {
|
||||||
|
throw new PermissionHandlerException("Could not load permissions provider service");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Vault provider and make sure it's valid
|
||||||
|
Permission vaultPerms = permissionProvider.getProvider();
|
||||||
|
if (vaultPerms == null) {
|
||||||
|
throw new PermissionHandlerException("Could not load Vault permissions provider");
|
||||||
|
}
|
||||||
|
return vaultPerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,6 +49,11 @@ public class VaultHandler implements PermissionHandler {
|
|||||||
return vaultProvider.has(player, node.getNode());
|
return vaultProvider.has(player, node.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
return vaultProvider.has("", name, node.getNode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
return vaultProvider.playerInGroup(player, group);
|
return vaultProvider.playerInGroup(player, group);
|
||||||
|
|||||||
@ -14,7 +14,12 @@ public class ZPermissionsHandler implements PermissionHandler {
|
|||||||
|
|
||||||
private ZPermissionsService zPermissionsService;
|
private ZPermissionsService zPermissionsService;
|
||||||
|
|
||||||
public ZPermissionsHandler(ZPermissionsService zPermissionsService) {
|
public ZPermissionsHandler() throws PermissionHandlerException {
|
||||||
|
// Set the zPermissions service and make sure it's valid
|
||||||
|
ZPermissionsService zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class);
|
||||||
|
if (zPermissionsService == null) {
|
||||||
|
throw new PermissionHandlerException("Failed to get the ZPermissions service!");
|
||||||
|
}
|
||||||
this.zPermissionsService = zPermissionsService;
|
this.zPermissionsService = zPermissionsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +42,15 @@ public class ZPermissionsHandler implements PermissionHandler {
|
|||||||
return node.getDefaultPermission().evaluate(player);
|
return node.getDefaultPermission().evaluate(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||||
|
Map<String, Boolean> perms = zPermissionsService.getPlayerPermissions(null, null, name);
|
||||||
|
if (perms.containsKey(node.getNode()))
|
||||||
|
return perms.get(node.getNode());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGroup(Player player, String group) {
|
public boolean isInGroup(Player player, String group) {
|
||||||
return getGroups(player).contains(group);
|
return getGroups(player).contains(group);
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import fr.xephi.authme.process.quit.AsynchronousQuit;
|
|||||||
import fr.xephi.authme.process.register.AsyncRegister;
|
import fr.xephi.authme.process.register.AsyncRegister;
|
||||||
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
|
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
|
||||||
import fr.xephi.authme.util.BukkitService;
|
import fr.xephi.authme.util.BukkitService;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -70,11 +71,20 @@ public class Management {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performUnregister(final Player player, final String password, final boolean isForce) {
|
public void performUnregister(final Player player, final String password) {
|
||||||
runTask(new Runnable() {
|
runTask(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
asynchronousUnregister.unregister(player, password, isForce);
|
asynchronousUnregister.unregister(player, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performUnregisterByAdmin(final CommandSender initiator, final String name, final Player player) {
|
||||||
|
runTask(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
asynchronousUnregister.adminUnregister(initiator, name, player);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -88,11 +98,11 @@ public class Management {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void performQuit(final Player player, final boolean isKick) {
|
public void performQuit(final Player player) {
|
||||||
runTask(new Runnable() {
|
runTask(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
asynchronousQuit.processQuit(player, isKick);
|
asynchronousQuit.processQuit(player);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user