mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2025-01-20 06:32:10 +01:00
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)
|
@ -12,9 +12,280 @@
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</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>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Project" />
|
||||
</component>
|
||||
</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>
|
||||
<hr>
|
||||
|
||||
#####News:
|
||||
|
||||
- Latest version of AuthMeBridge is finally compatible with latest AuthMe snapshots! ;)
|
||||
|
||||
#####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: [![Join the chat at https://gitter.im/Xephi/AuthMeReloaded](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
- 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: [![Build Status](https://travis-ci.org/AuthMe-Team/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/AuthMe-Team/AuthMeReloaded) [![Dependency Status](https://www.versioneye.com/user/projects/55bab9e8653762002000190a/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55bab9e8653762002000190a)
|
||||
- Build status: [![Build Status](https://travis-ci.org/AuthMe/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/AuthMe/AuthMeReloaded)
|
||||
|
||||
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/AuthMe-Team/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/AuthMe-Team/AuthMeReloaded)
|
||||
- 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/v/AuthMe-Team/AuthMeReloaded.svg)](https://jitpack.io/#AuthMe-Team/AuthMeReloaded)
|
||||
- Dependencies: [![Dependency Status](https://www.versioneye.com/user/projects/5617ca36a193340f28000222/badge.svg)](https://www.versioneye.com/user/projects/5617ca36a193340f28000222)
|
||||
|
||||
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/AuthMe/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/AuthMe/AuthMeReloaded)
|
||||
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
|
||||
- JitPack (just in case): [![](https://jitpack.io/v/AuthMe/AuthMeReloaded.svg)](https://jitpack.io/#AuthMe/AuthMeReloaded)
|
||||
|
||||
- Code Coverage: [![Coverage Status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
|
||||
|
||||
@ -39,6 +39,7 @@ McStats: http://mcstats.org/plugin/AuthMe
|
||||
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
|
||||
|
||||
#####Development history:
|
||||
Outdated!
|
||||
[![Gource AuthMe History Video](http://img.youtube.com/vi/hJRzNfYyd9k/hqdefault.jpg)](https://www.youtube.com/watch?v=hJRzNfYyd9k)
|
||||
|
||||
<hr>
|
||||
@ -53,8 +54,8 @@ McStats: http://mcstats.org/plugin/AuthMe
|
||||
>- Execute command "mvn clean install"
|
||||
|
||||
#####Running Requirements:
|
||||
>- Java 1.7 (should work also with Java 1.8)
|
||||
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X or 1.9.X)
|
||||
>- Java 1.7 or 1.8
|
||||
>- PaperSpigot, Spigot or CraftBukkit (1.7.10, 1.8.X, 1.9.X, 1.10.X)
|
||||
>- ProtocolLib (optional, required by the protectInventory feature)
|
||||
|
||||
<hr>
|
||||
@ -62,13 +63,16 @@ McStats: http://mcstats.org/plugin/AuthMe
|
||||
|
||||
#####"The best authentication plugin for the Bukkit/Spigot API!"
|
||||
|
||||
<p>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>
|
||||
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>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>
|
||||
<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>
|
||||
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.
|
||||
|
||||
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:
|
||||
<ul>
|
||||
@ -114,24 +118,25 @@ typing commands or using the inventory. It can also kick players with uncommonly
|
||||
####Email Recovery Dependency
|
||||
<a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-configure-email-recovery-system/">How to configure email recovery system?</a>
|
||||
####Commands
|
||||
<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
|
||||
<ul><li>authme.player.* - for all user commands
|
||||
</li><li>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>
|
||||
</li></ul>
|
||||
- authme.player.* - for all user commands
|
||||
- authme.admin.* - for all admin commands
|
||||
- [List of all permission nodes](http://github.com/AuthMe-Team/AuthMeReloaded/blob/master/docs/permission_nodes.md)
|
||||
|
||||
####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>
|
||||
</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>
|
||||
</li><li><a href="http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/">Website Integration</a>
|
||||
</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>
|
||||
</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>
|
||||
</li><li>Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
|
||||
</li></ul>
|
||||
- [How to install and set up](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-install-and-initial-configuration/)
|
||||
- [How to import database from xAuth](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-xauth/)
|
||||
- [Website integration](http://dev.bukkit.org/server-mods/authme-reloaded/pages/web-site-integration/)
|
||||
- [Click here for an example of the config file](https://raw.githubusercontent.com/Xephi/AuthMeReloaded/master/src/main/resources/config.yml)
|
||||
- [How to convert from Rakamak](http://dev.bukkit.org/server-mods/authme-reloaded/pages/how-to-import-database-from-rakamak/)
|
||||
- Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
|
||||
|
||||
<hr>
|
||||
|
||||
#####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>
|
||||
|
||||
#####Donate
|
||||
@ -144,6 +149,6 @@ GameHosting.it is leader in Italy as Game Server Provider. With its own DataCent
|
||||
[![GameHosting](http://www.gamehosting.it/images/bn3.png)](http://www.gamehosting.it)
|
||||
|
||||
#####Credits
|
||||
<p>Team members: look at the <a href="https://github.com/AuthMe-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>Thanks also to: AS1LV3RN1NJA, Hoeze and eprimex</p>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- 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
|
||||
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.
|
||||
<br />Requires `authme.player.register`
|
||||
- **/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`
|
||||
- **/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.
|
||||
<br />Requires `authme.player.changepassword`
|
||||
- **/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`
|
||||
- **/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 -->
|
||||
<!-- 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
|
||||
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 -->
|
||||
<!-- 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
|
||||
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.bypassantibot** – Permission node to bypass AntiBot protection.
|
||||
- **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.canbeforced** – Permission for users a login can be forced to.
|
||||
- **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.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
|
||||
|
220
pom.xml
220
pom.xml
@ -6,8 +6,7 @@
|
||||
|
||||
<groupId>fr.xephi</groupId>
|
||||
<artifactId>authme</artifactId>
|
||||
<version>5.2-BETA3</version>
|
||||
<packaging>jar</packaging>
|
||||
<version>5.2-SNAPSHOT</version>
|
||||
|
||||
<name>AuthMeReloaded</name>
|
||||
<description>The first authentication plugin for the Bukkit API!</description>
|
||||
@ -17,13 +16,13 @@
|
||||
|
||||
<organization>
|
||||
<name>AuthMe-Team</name>
|
||||
<url>https://github.com/AuthMe-Team</url>
|
||||
<url>https://github.com/AuthMe</url>
|
||||
</organization>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/AuthMe-Team/AuthMeReloaded.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:AuthMe-Team/AuthMeReloaded.git</developerConnection>
|
||||
<url>https://github.com/AuthMe-Team/AuthMeReloaded</url>
|
||||
<connection>scm:git:https://github.com/AuthMe/AuthMeReloaded.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:AuthMe/AuthMeReloaded.git</developerConnection>
|
||||
<url>https://github.com/AuthMe/AuthMeReloaded</url>
|
||||
</scm>
|
||||
|
||||
<ciManagement>
|
||||
@ -44,10 +43,6 @@
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.3.3</maven>
|
||||
</prerequisites>
|
||||
|
||||
<properties>
|
||||
<!-- Project properties -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -62,15 +57,17 @@
|
||||
|
||||
<!-- BukkitPlugin properties -->
|
||||
<bukkitplugin.name>${project.outputName}</bukkitplugin.name>
|
||||
<bukkitplugin.version>${project.versionCode}</bukkitplugin.version>
|
||||
<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! -->
|
||||
<bukkit.version>1.10-R0.1-SNAPSHOT</bukkit.version>
|
||||
</properties>
|
||||
|
||||
<!-- Jenkins profile (add the real buildNumber to the version string) -->
|
||||
<!-- Jenkins profile -->
|
||||
<profiles>
|
||||
<!-- Set the buildNumber using the jenkins env. variable -->
|
||||
<profile>
|
||||
<id>jenkins</id>
|
||||
<activation>
|
||||
@ -82,6 +79,7 @@
|
||||
<project.buildNumber>${env.BUILD_NUMBER}</project.buildNumber>
|
||||
</properties>
|
||||
</profile>
|
||||
<!-- Skip long hash tests, reduce the test time of 20-30 seconds -->
|
||||
<profile>
|
||||
<id>skipLongHashTests</id>
|
||||
<activation>
|
||||
@ -93,10 +91,85 @@
|
||||
<project.skipExtendedHashTests>true</project.skipExtendedHashTests>
|
||||
</properties>
|
||||
</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>
|
||||
|
||||
<build>
|
||||
<!-- Name of the NOSHADE jar (no shaded/relocated libraries) -->
|
||||
<!-- Name of the unshaded jar (no shaded/relocated libraries) -->
|
||||
<finalName>${project.finalName}-noshade</finalName>
|
||||
|
||||
<resources>
|
||||
@ -135,6 +208,7 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<configuration>
|
||||
<!-- Force the right file encoding during unit testing -->
|
||||
<argLine>-Dfile.encoding=${project.build.sourceEncoding} @{argLine}</argLine>
|
||||
<systemPropertyVariables>
|
||||
<project.skipExtendedHashTests>${project.skipExtendedHashTests}</project.skipExtendedHashTests>
|
||||
@ -143,20 +217,16 @@
|
||||
</plugin>
|
||||
<!-- Libs Shading and Relocation -->
|
||||
<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>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<!--
|
||||
Let's try to remove this!
|
||||
<minimizeJar>false</minimizeJar>
|
||||
-->
|
||||
</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>
|
||||
<!-- Spigot 1.8+ -->
|
||||
<execution>
|
||||
@ -170,33 +240,29 @@
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>com.google.guava:guava</exclude>
|
||||
<exclude>com.google.code.gson:gson</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
<!-- We use a newer version of gson so we need to include it! -->
|
||||
<relocation>
|
||||
<pattern>com.google.gson</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.google</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.hikari</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.zaxxer.hikari</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.slf4j</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.slf4j</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.slf4j.slf4j</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.maxmind.geoip</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.geoip</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.maxmind.geoip</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.ricecode.similarity</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>javax.inject</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||
</relocation>
|
||||
<!-- MCStats.org metrics -->
|
||||
<relocation>
|
||||
@ -215,31 +281,31 @@
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- Include all google libraries, because they are not available before 1.8 -->
|
||||
<relocations>
|
||||
<!-- Include all google libraries, because they are not available before 1.8 -->
|
||||
<relocation>
|
||||
<pattern>com.google</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.google</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.hikari</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.zaxxer.hikari</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.slf4j</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.slf4j</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.slf4j.slf4j</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.maxmind.geoip</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.geoip</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.maxmind.geoip</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.ricecode.similarity</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.similarity</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.ricecode.similarity</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>javax.inject</pattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.inject</shadedPattern>
|
||||
<shadedPattern>fr.xephi.authme.libs.javax.inject</shadedPattern>
|
||||
</relocation>
|
||||
<!-- MCStats.org metrics -->
|
||||
<relocation>
|
||||
@ -252,7 +318,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Exec Tools -->
|
||||
<!-- Exec Plugin (Tools runner) -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
@ -267,7 +333,7 @@
|
||||
<includeProjectDependencies>true</includeProjectDependencies>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Test coverage -->
|
||||
<!-- Coverage report generator -->
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
@ -281,7 +347,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Coveralls data -->
|
||||
<!-- Coverage report uploader -->
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
@ -289,9 +355,9 @@
|
||||
<configuration>
|
||||
<failOnServiceError>false</failOnServiceError>
|
||||
</configuration>
|
||||
<!-- The secret token is provided by console! -->
|
||||
<!-- The secret token is provided with a command-line parameter! -->
|
||||
</plugin>
|
||||
<!-- Javadocs settings -->
|
||||
<!-- JavaDocs generator -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
@ -305,9 +371,9 @@
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<!-- SpigotMC Repo (Bukkit and SpigotAPI) -->
|
||||
<!-- SpigotAPI Repo -->
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
|
||||
@ -319,7 +385,7 @@
|
||||
|
||||
<!-- CombatTagPlus Repo -->
|
||||
<repository>
|
||||
<id>minelink-thirdparty</id>
|
||||
<id>minelink-repo</id>
|
||||
<url>http://repo.minelink.net/content/repositories/public</url>
|
||||
</repository>
|
||||
|
||||
@ -331,33 +397,27 @@
|
||||
|
||||
<!-- Multiverse Repo -->
|
||||
<repository>
|
||||
<id>onarandombox</id>
|
||||
<id>onarandombox-repo</id>
|
||||
<url>http://repo.onarandombox.com/content/groups/public</url>
|
||||
</repository>
|
||||
|
||||
<!-- Vault Repo -->
|
||||
<repository>
|
||||
<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>
|
||||
|
||||
<!-- XAuth Repo -->
|
||||
<repository>
|
||||
<id>luricos-releases</id>
|
||||
<id>luricos-repo</id>
|
||||
<url>http://repo.luricos.de/content/repositories/releases</url>
|
||||
</repository>
|
||||
|
||||
<!-- Xephi Repo -->
|
||||
<!-- Our Repo (Many libs) -->
|
||||
<repository>
|
||||
<id>xephi-repo</id>
|
||||
<url>http://ci.xephi.fr/plugin/repository/everything/</url>
|
||||
</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>
|
||||
|
||||
<dependencies>
|
||||
@ -365,7 +425,7 @@
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>2.4.6</version>
|
||||
<version>2.4.7</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -375,6 +435,7 @@
|
||||
</exclusions>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- HikariCP Logger -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
@ -387,8 +448,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<!-- Can't use newer versions due to api changes! -->
|
||||
<version>2.0-beta9</version>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@ -401,11 +461,11 @@
|
||||
<optional>true</optional>
|
||||
</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>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.6.2</version>
|
||||
<version>2.2.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@ -453,38 +513,7 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Spigot API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||
<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>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>
|
||||
<!-- Moved in profiles! -->
|
||||
|
||||
<!-- ProtocolLib, http://dev.bukkit.org/bukkit-plugins/protocollib/ -->
|
||||
<dependency>
|
||||
@ -807,6 +836,13 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Injector -->
|
||||
<dependency>
|
||||
<groupId>ch.jalu</groupId>
|
||||
<artifactId>injector</artifactId>
|
||||
<version>0.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- String comparison library. Used for dynamic help system. -->
|
||||
<dependency>
|
||||
<groupId>net.ricecode</groupId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
* verification). Don't forget to update the AUTHME_TABLE value and your *
|
||||
* database credentials in getAuthmeMySqli(). *
|
||||
* *
|
||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
||||
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||
*****************************************************************************/
|
||||
abstract class AuthMeController {
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* ------------------------------------------------------- *
|
||||
* See AuthMeController for details. *
|
||||
* *
|
||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
||||
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||
***********************************************************/
|
||||
class Bcrypt extends AuthMeController {
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* ------------------------------------------------------- *
|
||||
* See AuthMeController for details. *
|
||||
* *
|
||||
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
|
||||
* Source: https://github.com/AuthMe/AuthMeReloaded/ *
|
||||
***********************************************************/
|
||||
class Sha256 extends AuthMeController {
|
||||
|
||||
|
@ -4,7 +4,7 @@ import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
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.util.BukkitService;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -20,16 +20,16 @@ import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
|
||||
*/
|
||||
public class AntiBot {
|
||||
|
||||
private final NewSetting settings;
|
||||
private final Settings settings;
|
||||
private final Messages messages;
|
||||
private final PermissionsManager permissionsManager;
|
||||
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 AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED;
|
||||
|
||||
@Inject
|
||||
AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager,
|
||||
AntiBot(Settings settings, Messages messages, PermissionsManager permissionsManager,
|
||||
BukkitService bukkitService) {
|
||||
this.settings = settings;
|
||||
this.messages = messages;
|
||||
@ -112,6 +112,27 @@ public class AntiBot {
|
||||
}, 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 {
|
||||
LISTENING,
|
||||
DISABLED,
|
||||
|
@ -1,146 +1,95 @@
|
||||
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.NewAPI;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
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.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.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.MetricsStarter;
|
||||
import fr.xephi.authme.listener.AuthMeBlockListener;
|
||||
import fr.xephi.authme.listener.AuthMeEntityListener;
|
||||
import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter;
|
||||
import fr.xephi.authme.listener.AuthMePlayerListener;
|
||||
import fr.xephi.authme.listener.AuthMePlayerListener16;
|
||||
import fr.xephi.authme.listener.AuthMePlayerListener18;
|
||||
import fr.xephi.authme.listener.AuthMeServerListener;
|
||||
import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter;
|
||||
import fr.xephi.authme.listener.AuthMeTablistPacketAdapter;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.output.ConsoleFilter;
|
||||
import fr.xephi.authme.output.Log4JFilter;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.initialization.Initializer;
|
||||
import fr.xephi.authme.initialization.MetricsManager;
|
||||
import fr.xephi.authme.initialization.OnShutdownPlayerSaver;
|
||||
import fr.xephi.authme.initialization.TaskCloser;
|
||||
import fr.xephi.authme.listener.BlockListener;
|
||||
import fr.xephi.authme.listener.EntityListener;
|
||||
import fr.xephi.authme.listener.PlayerListener;
|
||||
import fr.xephi.authme.listener.PlayerListener16;
|
||||
import fr.xephi.authme.listener.PlayerListener18;
|
||||
import fr.xephi.authme.listener.PlayerListener19;
|
||||
import fr.xephi.authme.listener.ServerListener;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.process.Management;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||
import fr.xephi.authme.security.crypts.SHA256;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
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.PurgeSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
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.task.PurgeTask;
|
||||
import fr.xephi.authme.task.CleanupTask;
|
||||
import fr.xephi.authme.task.purge.PurgeService;
|
||||
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.MigrationService;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
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.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
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.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.settings.properties.EmailSettings.MAIL_PASSWORD;
|
||||
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
|
||||
import static fr.xephi.authme.util.BukkitService.TICKS_PER_MINUTE;
|
||||
import static fr.xephi.authme.util.Utils.isClassLoaded;
|
||||
|
||||
/**
|
||||
* The AuthMe main class.
|
||||
*/
|
||||
public class AuthMe extends JavaPlugin {
|
||||
|
||||
// Defines the name of the plugin.
|
||||
// Constants
|
||||
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;
|
||||
private static String pluginVersion = "N/D";
|
||||
private static String pluginBuildNumber = "Unknown";
|
||||
|
||||
// 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 instances
|
||||
private CommandHandler commandHandler;
|
||||
private PermissionsManager permsMan;
|
||||
private NewSetting newSettings;
|
||||
private Settings settings;
|
||||
private Messages messages;
|
||||
private JsonCache playerBackup;
|
||||
private PasswordSecurity passwordSecurity;
|
||||
private DataSource database;
|
||||
private PluginHooks pluginHooks;
|
||||
private SpawnLoader spawnLoader;
|
||||
private boolean autoPurging;
|
||||
private BukkitService bukkitService;
|
||||
private AuthMeServiceInitializer initializer;
|
||||
private Injector injector;
|
||||
private GeoLiteAPI geoLiteApi;
|
||||
private PlayerCache playerCache;
|
||||
|
||||
/**
|
||||
* Get the plugin's instance.
|
||||
*
|
||||
* @return AuthMe
|
||||
* Constructor.
|
||||
*/
|
||||
@Deprecated
|
||||
public static AuthMe getInstance() {
|
||||
return plugin;
|
||||
public AuthMe() {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
private void setPluginInfos() {
|
||||
private void loadPluginInfo() {
|
||||
String versionRaw = this.getDescription().getVersion();
|
||||
int index = versionRaw.lastIndexOf("-");
|
||||
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
|
||||
public void onEnable() {
|
||||
// Set various instances
|
||||
plugin = this;
|
||||
ConsoleLogger.setLogger(getLogger());
|
||||
setPluginInfos();
|
||||
protected void instantiateServices(Injector injector) {
|
||||
// PlayerCache is still injected statically sometimes
|
||||
playerCache = PlayerCache.getInstance();
|
||||
injector.register(PlayerCache.class, playerCache);
|
||||
|
||||
// Load settings and custom configurations, if it fails, stop the server due to security reasons.
|
||||
newSettings = createNewSetting();
|
||||
if (newSettings == null) {
|
||||
getLogger().warning("Could not load configuration. Aborting.");
|
||||
getServer().shutdown();
|
||||
return;
|
||||
}
|
||||
ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log"));
|
||||
ConsoleLogger.setLoggingOptions(newSettings);
|
||||
messages = injector.getSingleton(Messages.class);
|
||||
permsMan = injector.getSingleton(PermissionsManager.class);
|
||||
bukkitService = injector.getSingleton(BukkitService.class);
|
||||
commandHandler = injector.getSingleton(CommandHandler.class);
|
||||
geoLiteApi = injector.getSingleton(GeoLiteAPI.class);
|
||||
|
||||
// Old settings manager
|
||||
if (!loadSettings()) {
|
||||
getServer().shutdown();
|
||||
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);
|
||||
}
|
||||
// Trigger construction of API classes; they will keep track of the singleton
|
||||
injector.getSingleton(NewAPI.class);
|
||||
injector.getSingleton(API.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,370 +250,105 @@ public class AuthMe extends JavaPlugin {
|
||||
*/
|
||||
private void showSettingsWarnings() {
|
||||
// Force single session disabled
|
||||
if (!newSettings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) {
|
||||
ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!");
|
||||
if (!settings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) {
|
||||
ConsoleLogger.warning("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!");
|
||||
}
|
||||
|
||||
// Session timeout disabled
|
||||
if (newSettings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0
|
||||
&& newSettings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
||||
ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!");
|
||||
if (settings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0
|
||||
&& settings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
|
||||
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
|
||||
PluginManager pluginManager = getServer().getPluginManager();
|
||||
|
||||
// Register event listeners
|
||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this);
|
||||
pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this);
|
||||
pluginManager.registerEvents(initializer.get(AuthMeEntityListener.class), this);
|
||||
pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this);
|
||||
pluginManager.registerEvents(injector.getSingleton(PlayerListener.class), this);
|
||||
pluginManager.registerEvents(injector.getSingleton(BlockListener.class), this);
|
||||
pluginManager.registerEvents(injector.getSingleton(EntityListener.class), this);
|
||||
pluginManager.registerEvents(injector.getSingleton(ServerListener.class), this);
|
||||
|
||||
// Try to register 1.6 player listeners
|
||||
try {
|
||||
Class.forName("org.bukkit.event.player.PlayerEditBookEvent");
|
||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener16.class), this);
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
if (isClassLoaded("org.bukkit.event.player.PlayerEditBookEvent")) {
|
||||
pluginManager.registerEvents(injector.getSingleton(PlayerListener16.class), this);
|
||||
}
|
||||
|
||||
// Try to register 1.8 player listeners
|
||||
try {
|
||||
Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent");
|
||||
pluginManager.registerEvents(initializer.get(AuthMePlayerListener18.class), this);
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
if (isClassLoaded("org.bukkit.event.player.PlayerInteractAtEntityEvent")) {
|
||||
pluginManager.registerEvents(injector.getSingleton(PlayerListener18.class), this);
|
||||
}
|
||||
|
||||
// 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() {
|
||||
if (database != null) {
|
||||
int playersOnline = bukkitService.getOnlinePlayers().size();
|
||||
if (playersOnline < 1) {
|
||||
if (playersOnline == 0) {
|
||||
database.purgeLogged();
|
||||
} else if (Settings.reloadSupport) {
|
||||
} else if (settings.getProperty(SecuritySettings.USE_RELOAD_COMMAND_SUPPORT)) {
|
||||
for (PlayerAuth auth : database.getLoggedPlayers()) {
|
||||
if (auth == null) {
|
||||
continue;
|
||||
}
|
||||
if (auth != null) {
|
||||
auth.setLastLogin(new Date().getTime());
|
||||
database.updateSession(auth);
|
||||
PlayerCache.getInstance().addPlayer(auth);
|
||||
playerCache.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
|
||||
public void onDisable() {
|
||||
// Save player data
|
||||
BukkitService bukkitService = initializer.getIfAvailable(BukkitService.class);
|
||||
LimboCache limboCache = initializer.getIfAvailable(LimboCache.class);
|
||||
|
||||
if (bukkitService != null && limboCache != null) {
|
||||
Collection<? extends Player> players = bukkitService.getOnlinePlayers();
|
||||
for (Player player : players) {
|
||||
savePlayer(player, limboCache);
|
||||
}
|
||||
// onDisable is also called when we prematurely abort, so any field may be null
|
||||
OnShutdownPlayerSaver onShutdownPlayerSaver = injector == null
|
||||
? null
|
||||
: injector.createIfHasDependencies(OnShutdownPlayerSaver.class);
|
||||
if (onShutdownPlayerSaver != null) {
|
||||
onShutdownPlayerSaver.saveAllPlayers();
|
||||
}
|
||||
|
||||
// Do backup on stop if enabled
|
||||
if (newSettings != null) {
|
||||
new PerformBackup(this, newSettings).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--;
|
||||
if (settings != null) {
|
||||
new PerformBackup(this, settings).doBackup(PerformBackup.BackupCause.STOP);
|
||||
}
|
||||
|
||||
progress++;
|
||||
getLogger().info("Progress: " + progress + " / " + pendingTasks.size());
|
||||
}
|
||||
if (database != null) {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
}, "AuthMe-DataSource#close").start();
|
||||
// Wait for tasks and close data source
|
||||
new Thread(
|
||||
new TaskCloser(this, database),
|
||||
"AuthMe-DataSource#close"
|
||||
).start();
|
||||
|
||||
// Disabled correctly
|
||||
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
|
||||
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) {
|
||||
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
|
||||
String ipAddress = Utils.getPlayerIp(player);
|
||||
@ -695,15 +359,15 @@ public class AuthMe extends JavaPlugin {
|
||||
.replace("{ONLINE}", playersOnline)
|
||||
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
|
||||
.replace("{IP}", ipAddress)
|
||||
.replace("{LOGINS}", Integer.toString(PlayerCache.getInstance().getLogged()))
|
||||
.replace("{LOGINS}", Integer.toString(playerCache.getLogged()))
|
||||
.replace("{WORLD}", player.getWorld().getName())
|
||||
.replace("{SERVER}", server.getServerName())
|
||||
.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.
|
||||
*
|
||||
@ -726,67 +390,4 @@ public class AuthMe extends JavaPlugin {
|
||||
// Handle the command
|
||||
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;
|
||||
|
||||
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.util.StringUtils;
|
||||
|
||||
@ -11,7 +13,6 @@ import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
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 DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
|
||||
private static Logger logger;
|
||||
private static boolean enableDebug = false;
|
||||
private static LogLevel logLevel = LogLevel.INFO;
|
||||
private static boolean useLogging = false;
|
||||
private static File logFile;
|
||||
private static FileWriter fileWriter;
|
||||
@ -30,17 +31,36 @@ public final class ConsoleLogger {
|
||||
private ConsoleLogger() {
|
||||
}
|
||||
|
||||
// --------
|
||||
// Configurations
|
||||
// --------
|
||||
|
||||
/**
|
||||
* Set the logger to use.
|
||||
*
|
||||
* @param logger The logger
|
||||
*/
|
||||
public static void setLogger(Logger logger) {
|
||||
ConsoleLogger.logger = logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file to log to if enabled.
|
||||
*
|
||||
* @param logFile The log file
|
||||
*/
|
||||
public static void setLogFile(File 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.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE);
|
||||
if (useLogging) {
|
||||
if (fileWriter == null) {
|
||||
try {
|
||||
@ -54,50 +74,99 @@ 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) {
|
||||
logger.info(message);
|
||||
if (useLogging) {
|
||||
writeLog(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
if (enableDebug) {
|
||||
//creating and filling an exception is a expensive call
|
||||
//TODO #419 20160601: ->so it should be removed as soon #419 is fixed
|
||||
//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);
|
||||
}
|
||||
}
|
||||
writeLog("[INFO] " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an error 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 String
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void showError(String message) {
|
||||
logger.warning(message);
|
||||
if (useLogging) {
|
||||
writeLog("ERROR: " + message);
|
||||
public static void fine(String message) {
|
||||
if (logLevel.includes(LogLevel.FINE)) {
|
||||
logger.info(message);
|
||||
writeLog("[FINE] " + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a message into the log file with a TimeStamp.
|
||||
* 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 String
|
||||
* @param message The message to log
|
||||
*/
|
||||
public static void debug(String message) {
|
||||
if (logLevel.includes(LogLevel.DEBUG)) {
|
||||
logger.info("Debug: " + message);
|
||||
writeLog("[DEBUG] " + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a Throwable with the provided message on WARNING level
|
||||
* and save the stack trace to the log file.
|
||||
*
|
||||
* @param message The message to accompany the exception
|
||||
* @param th The Throwable to log
|
||||
*/
|
||||
public static void logException(String message, Throwable th) {
|
||||
warning(message + " " + StringUtils.formatException(th));
|
||||
writeLog(Throwables.getStackTraceAsString(th));
|
||||
}
|
||||
|
||||
|
||||
// --------
|
||||
// Helpers
|
||||
// --------
|
||||
|
||||
/**
|
||||
* Close all file handles.
|
||||
*/
|
||||
public static void close() {
|
||||
if (fileWriter != null) {
|
||||
try {
|
||||
fileWriter.flush();
|
||||
fileWriter.close();
|
||||
fileWriter = null;
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
@ -111,37 +180,5 @@ public final class ConsoleLogger {
|
||||
} 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 th The Throwable to log
|
||||
*/
|
||||
public static void logException(String message, Throwable th) {
|
||||
showError(message + " " + StringUtils.formatException(th));
|
||||
writeStackTrace(th);
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
if (fileWriter != null) {
|
||||
try {
|
||||
fileWriter.flush();
|
||||
fileWriter.close();
|
||||
fileWriter = null;
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fr.xephi.authme;
|
||||
|
||||
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.DatabaseSettings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
@ -30,7 +30,7 @@ public class PerformBackup {
|
||||
private final String tblname;
|
||||
private final String path;
|
||||
private final File dataFolder;
|
||||
private final NewSetting settings;
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* Constructor for PerformBackup.
|
||||
@ -38,7 +38,7 @@ public class PerformBackup {
|
||||
* @param instance AuthMe
|
||||
* @param settings The plugin settings
|
||||
*/
|
||||
public PerformBackup(AuthMe instance, NewSetting settings) {
|
||||
public PerformBackup(AuthMe instance, Settings settings) {
|
||||
this.dataFolder = instance.getDataFolder();
|
||||
this.settings = settings;
|
||||
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
@ -60,7 +60,7 @@ public class PerformBackup {
|
||||
if (!settings.getProperty(BackupSettings.ENABLED)) {
|
||||
// Print a warning if the backup was requested via command or by another plugin
|
||||
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());
|
||||
}
|
||||
return;
|
||||
@ -76,7 +76,7 @@ public class PerformBackup {
|
||||
if (doBackup()) {
|
||||
ConsoleLogger.info("A backup has been performed successfully. Cause of the Backup: " + cause.name());
|
||||
} 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:
|
||||
return fileBackup(dbName + ".db");
|
||||
default:
|
||||
ConsoleLogger.showError("Unknown data source type '" + dataSourceType + "' for backup");
|
||||
ConsoleLogger.warning("Unknown data source type '" + dataSourceType + "' for backup");
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -113,7 +113,7 @@ public class PerformBackup {
|
||||
ConsoleLogger.info("Backup created successfully.");
|
||||
return true;
|
||||
} else {
|
||||
ConsoleLogger.showError("Could not create the backup! (Windows)");
|
||||
ConsoleLogger.warning("Could not create the backup! (Windows)");
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
ConsoleLogger.logException("Error during Windows backup:", e);
|
||||
@ -128,7 +128,7 @@ public class PerformBackup {
|
||||
ConsoleLogger.info("Backup created successfully.");
|
||||
return true;
|
||||
} else {
|
||||
ConsoleLogger.showError("Could not create the backup!");
|
||||
ConsoleLogger.warning("Could not create the backup!");
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
ConsoleLogger.logException("Error during backup:", e);
|
||||
@ -147,8 +147,7 @@ public class PerformBackup {
|
||||
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError("Encountered an error during file backup: " + StringUtils.formatException(ex));
|
||||
ConsoleLogger.writeStackTrace(ex);
|
||||
ConsoleLogger.logException("Encountered an error during file backup:", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -166,7 +165,7 @@ public class PerformBackup {
|
||||
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
|
||||
return true;
|
||||
} else {
|
||||
ConsoleLogger.showError("Mysql Windows Path is incorrect. Please check it");
|
||||
ConsoleLogger.warning("Mysql Windows Path is incorrect. Please check it");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,11 @@ import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
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.util.Utils;
|
||||
import fr.xephi.authme.util.ValidationService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -27,19 +28,21 @@ public class API {
|
||||
private static DataSource dataSource;
|
||||
private static PasswordSecurity passwordSecurity;
|
||||
private static Management management;
|
||||
private static PluginHooks pluginHooks;
|
||||
private static ValidationService validationService;
|
||||
|
||||
/**
|
||||
* Constructor for the deprecated API.
|
||||
*
|
||||
* @param instance AuthMe
|
||||
/*
|
||||
* Constructor.
|
||||
*/
|
||||
@Deprecated
|
||||
@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.dataSource = dataSource;
|
||||
API.passwordSecurity = passwordSecurity;
|
||||
API.management = management;
|
||||
API.pluginHooks = pluginHooks;
|
||||
API.validationService = validationService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,7 +50,6 @@ public class API {
|
||||
*
|
||||
* @return AuthMe instance
|
||||
*/
|
||||
@Deprecated
|
||||
public static AuthMe hookAuthMe() {
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
@ -66,7 +68,6 @@ public class API {
|
||||
* @param player The player to verify
|
||||
* @return true if the player is authenticated
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isAuthenticated(Player player) {
|
||||
return PlayerCache.getInstance().isAuthenticated(player.getName());
|
||||
}
|
||||
@ -77,12 +78,10 @@ public class API {
|
||||
* @param player The player to verify
|
||||
* @return true if the player is unrestricted
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isUnrestricted(Player player) {
|
||||
return Utils.isUnrestricted(player);
|
||||
return validationService.isUnrestricted(player.getName());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Location getLastLocation(Player player) {
|
||||
try {
|
||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName().toLowerCase());
|
||||
@ -99,7 +98,6 @@ public class API {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setPlayerInventory(Player player, ItemStack[] content,
|
||||
ItemStack[] armor) {
|
||||
try {
|
||||
@ -115,7 +113,6 @@ public class API {
|
||||
* @param playerName The player name to verify
|
||||
* @return true if player is registered
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isRegistered(String playerName) {
|
||||
String player = playerName.toLowerCase();
|
||||
return dataSource.isAuthAvailable(player);
|
||||
@ -128,7 +125,6 @@ public class API {
|
||||
* @param passwordToCheck The password to check
|
||||
* @return true if the password is correct, false otherwise
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean checkPassword(String playerName, String passwordToCheck) {
|
||||
return isRegistered(playerName) && passwordSecurity.comparePassword(passwordToCheck, playerName);
|
||||
}
|
||||
@ -140,7 +136,6 @@ public class API {
|
||||
* @param password The password
|
||||
* @return true if the player was registered correctly
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean registerPlayer(String playerName, String password) {
|
||||
String name = playerName.toLowerCase();
|
||||
HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
|
||||
@ -161,12 +156,10 @@ public class API {
|
||||
*
|
||||
* @param player The player to log in
|
||||
*/
|
||||
@Deprecated
|
||||
public static void forceLogin(Player player) {
|
||||
management.performLogin(player, "dontneed", true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public AuthMe getPlugin() {
|
||||
return instance;
|
||||
}
|
||||
@ -177,9 +170,8 @@ public class API {
|
||||
* @param player The player to verify
|
||||
* @return true if player is an npc
|
||||
*/
|
||||
@Deprecated
|
||||
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.cache.auth.PlayerAuth;
|
||||
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.util.Utils;
|
||||
import fr.xephi.authme.util.ValidationService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -22,35 +25,42 @@ public class NewAPI {
|
||||
|
||||
public static NewAPI singleton;
|
||||
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.
|
||||
*
|
||||
* @param plugin The AuthMe plugin instance
|
||||
*/
|
||||
@Inject
|
||||
public NewAPI(AuthMe plugin) {
|
||||
NewAPI(AuthMe plugin, PluginHooks pluginHooks, DataSource dataSource, PasswordSecurity passwordSecurity,
|
||||
Management management, ValidationService validationService, PlayerCache playerCache) {
|
||||
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.
|
||||
*
|
||||
* @return The API object, or null if the AuthMe plugin instance could not be retrieved
|
||||
* from the server environment
|
||||
* @return The API object, or null if the AuthMe plugin is not enabled or not fully initialized yet
|
||||
*/
|
||||
public static NewAPI getInstance() {
|
||||
if (singleton != null) {
|
||||
return singleton;
|
||||
}
|
||||
Plugin p = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
|
||||
if (p == null || !(p instanceof AuthMe)) {
|
||||
// NewAPI is initialized in AuthMe#onEnable -> if singleton is null,
|
||||
// it means AuthMe isn't initialized (yet)
|
||||
return null;
|
||||
}
|
||||
AuthMe authme = (AuthMe) p;
|
||||
singleton = new NewAPI(authme);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the plugin instance.
|
||||
@ -78,7 +88,7 @@ public class NewAPI {
|
||||
* @return true if the player is authenticated
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
* @return Location The location of the player
|
||||
*/
|
||||
public Location getLastLocation(Player player) {
|
||||
PlayerAuth auth = PlayerCache.getInstance().getAuth(player.getName());
|
||||
PlayerAuth auth = playerCache.getAuth(player.getName());
|
||||
if (auth != null) {
|
||||
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) {
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
String name = playerName.toLowerCase();
|
||||
HashedPassword result = plugin.getPasswordSecurity().computeHash(password, name);
|
||||
HashedPassword result = passwordSecurity.computeHash(password, name);
|
||||
if (isRegistered(name)) {
|
||||
return false;
|
||||
}
|
||||
@ -158,7 +168,7 @@ public class NewAPI {
|
||||
.password(result)
|
||||
.realName(playerName)
|
||||
.build();
|
||||
return plugin.getDataSource().saveAuth(auth);
|
||||
return dataSource.saveAuth(auth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,7 +177,7 @@ public class NewAPI {
|
||||
* @param player The player to log in
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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?
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.security.RandomString;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -21,10 +21,10 @@ public class CaptchaManager implements SettingsDependent {
|
||||
private int captchaLength;
|
||||
|
||||
@Inject
|
||||
CaptchaManager(NewSetting settings) {
|
||||
CaptchaManager(Settings settings) {
|
||||
this.playerCounts = new ConcurrentHashMap<>();
|
||||
this.captchaCodes = new ConcurrentHashMap<>();
|
||||
loadSettings(settings);
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,7 +123,7 @@ public class CaptchaManager implements SettingsDependent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings(NewSetting settings) {
|
||||
public void reload(Settings settings) {
|
||||
this.isEnabled = settings.getProperty(SecuritySettings.USE_CAPTCHA);
|
||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TRIES_BEFORE_CAPTCHA);
|
||||
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.output.MessageKey;
|
||||
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.util.BukkitService;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
@ -30,11 +30,11 @@ public class TempbanManager implements SettingsDependent {
|
||||
private int length;
|
||||
|
||||
@Inject
|
||||
TempbanManager(BukkitService bukkitService, Messages messages, NewSetting settings) {
|
||||
TempbanManager(BukkitService bukkitService, Messages messages, Settings settings) {
|
||||
this.ipLoginFailureCounts = new ConcurrentHashMap<>();
|
||||
this.bukkitService = bukkitService;
|
||||
this.messages = messages;
|
||||
loadSettings(settings);
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +108,7 @@ public class TempbanManager implements SettingsDependent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings(NewSetting settings) {
|
||||
public void reload(Settings settings) {
|
||||
this.isEnabled = settings.getProperty(SecuritySettings.TEMPBAN_ON_MAX_LOGINS);
|
||||
this.threshold = settings.getProperty(SecuritySettings.MAX_LOGIN_TEMPBAN);
|
||||
this.length = settings.getProperty(SecuritySettings.TEMPBAN_LENGTH);
|
||||
|
@ -85,6 +85,13 @@ public class PlayerAuth {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setQuitLocation(Location location) {
|
||||
x = location.getBlockX();
|
||||
y = location.getBlockY();
|
||||
z = location.getBlockZ();
|
||||
world = location.getWorld().getName();
|
||||
}
|
||||
|
||||
public double getQuitLocX() {
|
||||
return x;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package fr.xephi.authme.cache.auth;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Used to manage player's Authenticated status
|
||||
*/
|
||||
public class PlayerCache {
|
||||
|
||||
@ -34,7 +34,6 @@ public class PlayerCache {
|
||||
* @param auth PlayerAuth
|
||||
*/
|
||||
public void addPlayer(PlayerAuth auth) {
|
||||
ConsoleLogger.debug("ADDED PLAYER TO CACHE " + auth.getNickname());
|
||||
cache.put(auth.getNickname().toLowerCase(), auth);
|
||||
}
|
||||
|
||||
@ -44,7 +43,6 @@ public class PlayerCache {
|
||||
* @param auth PlayerAuth
|
||||
*/
|
||||
public void updatePlayer(PlayerAuth auth) {
|
||||
ConsoleLogger.debug("UPDATE PLAYER " + auth.getNickname());
|
||||
cache.put(auth.getNickname(), auth);
|
||||
}
|
||||
|
||||
@ -54,16 +52,15 @@ public class PlayerCache {
|
||||
* @param user String
|
||||
*/
|
||||
public void removePlayer(String user) {
|
||||
ConsoleLogger.debug("REMOVE PLAYER " + user);
|
||||
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) {
|
||||
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;
|
||||
|
||||
import fr.xephi.authme.cache.backup.JsonCache;
|
||||
import fr.xephi.authme.cache.backup.PlayerData;
|
||||
import fr.xephi.authme.cache.backup.PlayerDataStorage;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
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.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Manages all {@link LimboPlayer} instances.
|
||||
* Manages all {@link PlayerData} instances.
|
||||
*/
|
||||
public class LimboCache {
|
||||
|
||||
private final ConcurrentHashMap<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
||||
private final JsonCache jsonCache = new JsonCache();
|
||||
private final Map<String, PlayerData> cache = new ConcurrentHashMap<>();
|
||||
|
||||
@Inject
|
||||
private PlayerDataStorage playerDataStorage;
|
||||
private Settings settings;
|
||||
private PermissionsManager permissionsManager;
|
||||
@Inject
|
||||
private SpawnLoader spawnLoader;
|
||||
|
||||
@Inject
|
||||
LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader) {
|
||||
LimboCache(Settings settings, PermissionsManager permissionsManager,
|
||||
SpawnLoader spawnLoader, PlayerDataStorage playerDataStorage) {
|
||||
this.settings = settings;
|
||||
this.permissionsManager = permissionsManager;
|
||||
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.
|
||||
*/
|
||||
public void addLimboPlayer(Player player) {
|
||||
public void addPlayerData(Player player) {
|
||||
String name = player.getName().toLowerCase();
|
||||
Location location = player.isDead() ? spawnLoader.getSpawnLocation(player) : player.getLocation();
|
||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||
boolean operator = player.isOp();
|
||||
boolean flyEnabled = player.getAllowFlight();
|
||||
float walkSpeed = player.getWalkSpeed();
|
||||
float flySpeed = player.getFlySpeed();
|
||||
String playerGroup = "";
|
||||
if (permissionsManager.hasGroupSupport()) {
|
||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
||||
}
|
||||
|
||||
if (jsonCache.doesCacheExist(player)) {
|
||||
PlayerData cache = jsonCache.readCache(player);
|
||||
if (playerDataStorage.hasData(player)) {
|
||||
PlayerData cache = playerDataStorage.readData(player);
|
||||
if (cache != null) {
|
||||
location = cache.getLocation();
|
||||
playerGroup = cache.getGroup();
|
||||
operator = cache.getOperator();
|
||||
flyEnabled = cache.isFlyEnabled();
|
||||
operator = cache.isOperator();
|
||||
flyEnabled = cache.isCanFly();
|
||||
walkSpeed = cache.getWalkSpeed();
|
||||
flySpeed = cache.getFlySpeed();
|
||||
}
|
||||
} else {
|
||||
playerDataStorage.saveData(player);
|
||||
}
|
||||
|
||||
|
||||
cache.put(name, new LimboPlayer(name, location, operator, playerGroup, flyEnabled));
|
||||
cache.put(name, new PlayerData(location, operator, playerGroup, flyEnabled, walkSpeed, flySpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method deleteLimboPlayer.
|
||||
* Restore player's data to player if exist.
|
||||
*
|
||||
* @param name String
|
||||
* @param player Player instance to restore
|
||||
*/
|
||||
public void deleteLimboPlayer(String name) {
|
||||
checkNotNull(name);
|
||||
name = name.toLowerCase();
|
||||
LimboPlayer cachedPlayer = cache.remove(name);
|
||||
public void restoreData(Player player) {
|
||||
String lowerName = player.getName().toLowerCase();
|
||||
if (cache.containsKey(lowerName)) {
|
||||
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) {
|
||||
cachedPlayer.clearTasks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getLimboPlayer.
|
||||
* Method getPlayerData.
|
||||
*
|
||||
* @param name String
|
||||
*
|
||||
* @return LimboPlayer
|
||||
* @return PlayerData
|
||||
*/
|
||||
public LimboPlayer getLimboPlayer(String name) {
|
||||
public PlayerData getPlayerData(String name) {
|
||||
checkNotNull(name);
|
||||
return cache.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method hasLimboPlayer.
|
||||
* Method hasPlayerData.
|
||||
*
|
||||
* @param name String
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean hasLimboPlayer(String name) {
|
||||
public boolean hasPlayerData(String name) {
|
||||
checkNotNull(name);
|
||||
return cache.containsKey(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updateLimboPlayer.
|
||||
* Method updatePlayerData.
|
||||
*
|
||||
* @param player Player
|
||||
*/
|
||||
public void updateLimboPlayer(Player player) {
|
||||
public void updatePlayerData(Player player) {
|
||||
checkNotNull(player);
|
||||
deleteLimboPlayer(player.getName().toLowerCase());
|
||||
addLimboPlayer(player);
|
||||
removeFromCache(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)
|
||||
* 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 fly;
|
||||
private Location loc = null;
|
||||
private final boolean canFly;
|
||||
private final boolean operator;
|
||||
private final String group;
|
||||
private final Location loc;
|
||||
private final float walkSpeed;
|
||||
private final float flySpeed;
|
||||
private BukkitTask timeoutTask = null;
|
||||
private BukkitTask messageTask = null;
|
||||
private boolean operator = false;
|
||||
private String group;
|
||||
|
||||
public LimboPlayer(String name, Location loc, boolean operator,
|
||||
String group, boolean fly) {
|
||||
this.name = name;
|
||||
public PlayerData(Location loc, boolean operator,
|
||||
String group, boolean fly, float walkSpeed, float flySpeed) {
|
||||
this.loc = loc;
|
||||
this.operator = operator;
|
||||
this.group = group;
|
||||
this.fly = fly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the player.
|
||||
*
|
||||
* @return The player's name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
this.canFly = fly;
|
||||
this.walkSpeed = walkSpeed;
|
||||
this.flySpeed = flySpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,7 +33,7 @@ public class LimboPlayer {
|
||||
*
|
||||
* @return The player's location
|
||||
*/
|
||||
public Location getLoc() {
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
@ -62,8 +55,16 @@ public class LimboPlayer {
|
||||
return group;
|
||||
}
|
||||
|
||||
public boolean isFly() {
|
||||
return fly;
|
||||
public boolean isCanFly() {
|
||||
return canFly;
|
||||
}
|
||||
|
||||
public float getWalkSpeed() {
|
||||
return walkSpeed;
|
||||
}
|
||||
|
||||
public float getFlySpeed() {
|
||||
return flySpeed;
|
||||
}
|
||||
|
||||
/**
|
@ -1,8 +1,8 @@
|
||||
package fr.xephi.authme.command;
|
||||
|
||||
import ch.jalu.injector.Injector;
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.command.help.HelpProvider;
|
||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
@ -37,12 +37,12 @@ public class CommandHandler {
|
||||
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> commands = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
public CommandHandler(AuthMeServiceInitializer initializer, CommandMapper commandMapper,
|
||||
public CommandHandler(Injector injector, CommandMapper commandMapper,
|
||||
PermissionsManager permissionsManager, HelpProvider helpProvider) {
|
||||
this.commandMapper = commandMapper;
|
||||
this.permissionsManager = permissionsManager;
|
||||
this.helpProvider = helpProvider;
|
||||
initializeCommands(initializer, commandMapper.getCommandClasses());
|
||||
initializeCommands(injector, commandMapper.getCommandClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,12 +90,13 @@ public class CommandHandler {
|
||||
/**
|
||||
* Initialize all required ExecutableCommand objects.
|
||||
*
|
||||
* @param injector the injector
|
||||
* @param commandClasses the classes to instantiate
|
||||
*/
|
||||
private void initializeCommands(AuthMeServiceInitializer initializer,
|
||||
private void initializeCommands(Injector injector,
|
||||
Set<Class<? extends ExecutableCommand>> 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.Messages;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.domain.Property;
|
||||
import fr.xephi.authme.util.ValidationService;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -18,7 +18,7 @@ public class CommandService {
|
||||
@Inject
|
||||
private Messages messages;
|
||||
@Inject
|
||||
private NewSetting settings;
|
||||
private Settings settings;
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@ -53,6 +53,16 @@ public class CommandService {
|
||||
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.
|
||||
*
|
||||
@ -69,7 +79,7 @@ public class CommandService {
|
||||
*
|
||||
* @return The settings manager
|
||||
*/
|
||||
public NewSetting getSettings() {
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
|
||||
|
||||
if (dataSource.updatePassword(auth)) {
|
||||
commandService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
|
||||
ConsoleLogger.info(playerNameLowerCase + "'s password changed");
|
||||
ConsoleLogger.info(sender.getName() + " changed password of " + playerNameLowerCase);
|
||||
} else {
|
||||
commandService.send(sender, MessageKey.ERROR);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import ch.jalu.injector.Injector;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.command.CommandService;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
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.vAuthConverter;
|
||||
import fr.xephi.authme.converter.xAuthConverter;
|
||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -30,7 +31,7 @@ public class ConverterCommand implements ExecutableCommand {
|
||||
private BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
private AuthMeServiceInitializer initializer;
|
||||
private Injector injector;
|
||||
|
||||
@Override
|
||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||
@ -45,13 +46,17 @@ public class ConverterCommand implements ExecutableCommand {
|
||||
}
|
||||
|
||||
// Get the proper converter instance
|
||||
final Converter converter = initializer.newInstance(jobType.getConverterClass());
|
||||
final Converter converter = injector.newInstance(jobType.getConverterClass());
|
||||
|
||||
// Run the convert job
|
||||
bukkitService.runTaskAsynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
converter.execute(sender);
|
||||
} catch (Exception e) {
|
||||
ConsoleLogger.logException("Error during conversion:", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,11 +1,8 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.task.PurgeTask;
|
||||
import fr.xephi.authme.task.purge.PurgeService;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@ -21,10 +18,7 @@ import java.util.Set;
|
||||
public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
||||
|
||||
@Inject
|
||||
private DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
private AuthMe plugin;
|
||||
private PurgeService purgeService;
|
||||
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
@ -32,18 +26,12 @@ public class PurgeBannedPlayersCommand implements ExecutableCommand {
|
||||
@Override
|
||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||
// Get the list of banned players
|
||||
Set<String> namedBanned = new HashSet<>();
|
||||
Set<OfflinePlayer> bannedPlayers = bukkitService.getBannedPlayers();
|
||||
Set<String> namedBanned = new HashSet<>(bannedPlayers.size());
|
||||
for (OfflinePlayer offlinePlayer : bannedPlayers) {
|
||||
namedBanned.add(offlinePlayer.getName().toLowerCase());
|
||||
}
|
||||
|
||||
//todo: note this should may run async because it may executes a SQL-Query
|
||||
// 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);
|
||||
purgeService.purgePlayers(sender, namedBanned, bannedPlayers.toArray(new OfflinePlayer[bannedPlayers.size()]));
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,13 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.task.PurgeTask;
|
||||
import fr.xephi.authme.task.purge.PurgeService;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@Inject
|
||||
private DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
private AuthMe plugin;
|
||||
private PurgeService purgeService;
|
||||
|
||||
@Override
|
||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||
@ -52,13 +46,7 @@ public class PurgeCommand implements ExecutableCommand {
|
||||
calendar.add(Calendar.DATE, -days);
|
||||
long until = calendar.getTimeInMillis();
|
||||
|
||||
//todo: note this should may run async because it may executes a SQL-Query
|
||||
// Purge the data, get the purged values
|
||||
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);
|
||||
// Run the purge
|
||||
purgeService.runPurge(sender, until);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
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.ExecutableCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
@ -37,6 +38,9 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Override
|
||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||
// Get the player name and password
|
||||
@ -79,7 +83,8 @@ public class RegisterAdminCommand implements ExecutableCommand {
|
||||
bukkitService.scheduleSyncDelayedTask(new Runnable() {
|
||||
@Override
|
||||
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;
|
||||
|
||||
import ch.jalu.injector.Injector;
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.command.CommandService;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
||||
import fr.xephi.authme.initialization.Reloadable;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
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 org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -23,10 +26,10 @@ public class ReloadCommand implements ExecutableCommand {
|
||||
private AuthMe plugin;
|
||||
|
||||
@Inject
|
||||
private AuthMeServiceInitializer initializer;
|
||||
private Injector injector;
|
||||
|
||||
@Inject
|
||||
private NewSetting settings;
|
||||
private Settings settings;
|
||||
|
||||
@Inject
|
||||
private DataSource dataSource;
|
||||
@ -44,7 +47,7 @@ public class ReloadCommand implements ExecutableCommand {
|
||||
ConsoleLogger.info("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);
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
|
||||
@ -52,4 +55,16 @@ public class ReloadCommand implements ExecutableCommand {
|
||||
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;
|
||||
|
||||
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.ExecutableCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.permission.AuthGroupHandler;
|
||||
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.process.Management;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
import static fr.xephi.authme.util.BukkitService.TICKS_PER_SECOND;
|
||||
|
||||
/**
|
||||
* Admin command to unregister a player.
|
||||
*/
|
||||
@ -35,74 +23,27 @@ public class UnregisterAdminCommand implements ExecutableCommand {
|
||||
@Inject
|
||||
private CommandService commandService;
|
||||
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
@Inject
|
||||
private LimboPlayerTaskManager limboPlayerTaskManager;
|
||||
|
||||
@Inject
|
||||
private AuthGroupHandler authGroupHandler;
|
||||
private Management management;
|
||||
|
||||
UnregisterAdminCommand() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeCommand(final CommandSender sender, List<String> arguments) {
|
||||
// Get the player name
|
||||
String playerName = arguments.get(0);
|
||||
String playerNameLowerCase = playerName.toLowerCase();
|
||||
|
||||
// Make sure the user is valid
|
||||
if (!dataSource.isAuthAvailable(playerNameLowerCase)) {
|
||||
// Make sure the user exists
|
||||
if (!dataSource.isAuthAvailable(playerName)) {
|
||||
commandService.send(sender, MessageKey.UNKNOWN_USER);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the player
|
||||
if (!dataSource.removeAuth(playerNameLowerCase)) {
|
||||
commandService.send(sender, MessageKey.ERROR);
|
||||
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));
|
||||
}
|
||||
// Get the player from the server and perform unregister
|
||||
Player target = bukkitService.getPlayerExact(playerName);
|
||||
management.performUnregisterByAdmin(sender, playerName, target);
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,13 @@ public class VersionCommand implements ExecutableCommand {
|
||||
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
|
||||
sender.sendMessage(ChatColor.GOLD + "Developers:");
|
||||
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, "games647", "games647", "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 +
|
||||
"http://dev.bukkit.org/bukkit-plugins/authme-reloaded/");
|
||||
sender.sendMessage(ChatColor.GOLD + "License: " + ChatColor.WHITE + "GNU GPL v3.0"
|
||||
|
@ -47,7 +47,6 @@ public class ChangePasswordCommand extends PlayerCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO ljacqu 20160117: Call async task via Management
|
||||
management.performPasswordChange(player, oldPassword, newPassword);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
package fr.xephi.authme.command.executable.email;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.command.CommandService;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.RandomString;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -33,53 +32,39 @@ public class RecoverEmailCommand extends PlayerCommand {
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
// TODO #655: Remove injected AuthMe instance once Authme#mail is encapsulated
|
||||
private AuthMe plugin;
|
||||
private SendMailSSL sendMailSsl;
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
final String playerMail = arguments.get(0);
|
||||
final String playerName = player.getName();
|
||||
|
||||
if (plugin.mail == null) {
|
||||
ConsoleLogger.showError("Mail API is not set");
|
||||
commandService.send(player, MessageKey.ERROR);
|
||||
if (!sendMailSsl.hasAllInformation()) {
|
||||
ConsoleLogger.warning("Mail API is not set");
|
||||
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||
return;
|
||||
}
|
||||
if (dataSource.isAuthAvailable(playerName)) {
|
||||
if (PlayerCache.getInstance().isAuthenticated(playerName)) {
|
||||
if (playerCache.isAuthenticated(playerName)) {
|
||||
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
sendMailSsl.sendPasswordMail(auth, thePass);
|
||||
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
|
||||
} else {
|
||||
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.register;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.command.CommandService;
|
||||
import fr.xephi.authme.command.PlayerCommand;
|
||||
import fr.xephi.authme.mail.SendMailSSL;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.process.Management;
|
||||
import fr.xephi.authme.security.HashAlgorithm;
|
||||
@ -27,6 +28,9 @@ public class RegisterCommand extends PlayerCommand {
|
||||
@Inject
|
||||
private CommandService commandService;
|
||||
|
||||
@Inject
|
||||
private SendMailSSL sendMailSsl;
|
||||
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
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) {
|
||||
if (commandService.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
|
||||
player.sendMessage("Cannot register: no email address is set for the server. "
|
||||
+ "Please contact an administrator");
|
||||
ConsoleLogger.showError("Cannot register player '" + player.getName() + "': no email is set "
|
||||
+ "to send emails from. Please add one in your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
||||
if (!sendMailSsl.hasAllInformation()) {
|
||||
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
|
||||
ConsoleLogger.warning("Cannot register player '" + player.getName() + "': no email or password is set "
|
||||
+ "to send emails from. Please adjust your config at " + EmailSettings.MAIL_ACCOUNT.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,9 @@ import org.bukkit.entity.Player;
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Command for a player to unregister himself.
|
||||
*/
|
||||
public class UnregisterCommand extends PlayerCommand {
|
||||
|
||||
@Inject
|
||||
@ -24,15 +27,15 @@ public class UnregisterCommand extends PlayerCommand {
|
||||
@Override
|
||||
public void runCommand(Player player, List<String> arguments) {
|
||||
String playerPass = arguments.get(0);
|
||||
final String playerNameLowerCase = player.getName().toLowerCase();
|
||||
final String playerName = player.getName();
|
||||
|
||||
// Make sure the player is authenticated
|
||||
if (!playerCache.isAuthenticated(playerNameLowerCase)) {
|
||||
if (!playerCache.isAuthenticated(playerName)) {
|
||||
commandService.send(player, MessageKey.NOT_LOGGED_IN);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.PermissionNode;
|
||||
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 org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -48,9 +48,9 @@ public class HelpProvider implements SettingsDependent {
|
||||
private String helpHeader;
|
||||
|
||||
@Inject
|
||||
HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
|
||||
HelpProvider(PermissionsManager permissionsManager, Settings settings) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
loadSettings(settings);
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
private List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
|
||||
@ -102,7 +102,7 @@ public class HelpProvider implements SettingsDependent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings(NewSetting settings) {
|
||||
public void reload(Settings settings) {
|
||||
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.datasource.DataSource;
|
||||
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 org.bukkit.command.CommandSender;
|
||||
|
||||
@ -20,11 +20,11 @@ import java.io.IOException;
|
||||
public class CrazyLoginConverter implements Converter {
|
||||
|
||||
private final DataSource database;
|
||||
private final NewSetting settings;
|
||||
private final Settings settings;
|
||||
private final File dataFolder;
|
||||
|
||||
@Inject
|
||||
CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings) {
|
||||
CrazyLoginConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings) {
|
||||
this.dataFolder = dataFolder;
|
||||
this.database = dataSource;
|
||||
this.settings = settings;
|
||||
@ -61,7 +61,7 @@ public class CrazyLoginConverter implements Converter {
|
||||
}
|
||||
ConsoleLogger.info("CrazyLogin database has been imported correctly");
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class ForceFlatToSqlite {
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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.security.PasswordSecurity;
|
||||
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 org.bukkit.command.CommandSender;
|
||||
|
||||
@ -24,12 +24,12 @@ import java.util.Map.Entry;
|
||||
public class RakamakConverter implements Converter {
|
||||
|
||||
private final DataSource database;
|
||||
private final NewSetting settings;
|
||||
private final Settings settings;
|
||||
private final File pluginFolder;
|
||||
private final PasswordSecurity passwordSecurity;
|
||||
|
||||
@Inject
|
||||
RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, NewSetting settings,
|
||||
RakamakConverter(@DataFolder File dataFolder, DataSource dataSource, Settings settings,
|
||||
PasswordSecurity passwordSecurity) {
|
||||
this.database = dataSource;
|
||||
this.settings = settings;
|
||||
@ -82,15 +82,14 @@ public class RakamakConverter implements Converter {
|
||||
.realName(playerName)
|
||||
.ip(ip)
|
||||
.password(psw)
|
||||
.lastLogin(System.currentTimeMillis())
|
||||
.lastLogin(0)
|
||||
.build();
|
||||
database.saveAuth(auth);
|
||||
}
|
||||
ConsoleLogger.info("Rakamak database has been imported correctly");
|
||||
sender.sendMessage("Rakamak database has been imported correctly");
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
sender.sendMessage("Can't open the rakamak database file! Does it exist?");
|
||||
ConsoleLogger.logException("Can't open the rakamak database file! Does it exist?", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,19 +7,19 @@ import fr.xephi.authme.datasource.DataSourceType;
|
||||
import fr.xephi.authme.datasource.SQLite;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class SqliteToSql implements Converter {
|
||||
|
||||
private final NewSetting settings;
|
||||
private final Settings settings;
|
||||
private final DataSource dataSource;
|
||||
private final Messages messages;
|
||||
|
||||
@Inject
|
||||
SqliteToSql(NewSetting settings, DataSource dataSource, Messages messages) {
|
||||
SqliteToSql(Settings settings, DataSource dataSource, Messages messages) {
|
||||
this.settings = settings;
|
||||
this.dataSource = dataSource;
|
||||
this.messages = messages;
|
||||
|
@ -1,28 +1,77 @@
|
||||
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 fr.xephi.authme.initialization.DataFolder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
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 {
|
||||
|
||||
private final AuthMe plugin;
|
||||
private final DataSource dataSource;
|
||||
private final File vAuthPasswordsFile;
|
||||
|
||||
@Inject
|
||||
vAuthConverter(AuthMe plugin) {
|
||||
this.plugin = plugin;
|
||||
vAuthConverter(@DataFolder File dataFolder, DataSource dataSource) {
|
||||
vAuthPasswordsFile = new File(dataFolder.getParent(), makePath("vAuth", "passwords.yml"));
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
try (Scanner scanner = new Scanner(vAuthPasswordsFile)) {
|
||||
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 {
|
||||
new vAuthFileReader(plugin).convert();
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage(e.getMessage());
|
||||
ConsoleLogger.showError(e.getMessage());
|
||||
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;
|
||||
|
||||
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.plugin.PluginManager;
|
||||
|
||||
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 {
|
||||
|
||||
private final AuthMe plugin;
|
||||
|
||||
@Inject
|
||||
xAuthConverter(AuthMe plugin) {
|
||||
this.plugin = plugin;
|
||||
@DataFolder
|
||||
private File dataFolder;
|
||||
@Inject
|
||||
private DataSource database;
|
||||
@Inject
|
||||
private PluginManager pluginManager;
|
||||
|
||||
xAuthConverter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
try {
|
||||
Class.forName("de.luricos.bukkit.xAuth.xAuth");
|
||||
xAuthToFlat converter = new xAuthToFlat(plugin, sender);
|
||||
converter.convert();
|
||||
convert(sender);
|
||||
} catch (ClassNotFoundException ce) {
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
@ -54,7 +55,6 @@ public class CacheDataSource implements DataSource {
|
||||
return executorService.submit(new Callable<Optional<PlayerAuth>>() {
|
||||
@Override
|
||||
public Optional<PlayerAuth> call() {
|
||||
ConsoleLogger.debug("REFRESH " + key);
|
||||
return load(key);
|
||||
}
|
||||
});
|
||||
@ -139,13 +139,8 @@ public class CacheDataSource implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> autoPurgeDatabase(long until) {
|
||||
Set<String> cleared = source.autoPurgeDatabase(until);
|
||||
for (String name : cleared) {
|
||||
cachedAuths.invalidate(name);
|
||||
}
|
||||
|
||||
return cleared;
|
||||
public Set<String> getRecordsToPurge(long until) {
|
||||
return source.getRecordsToPurge(until);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -160,14 +155,14 @@ public class CacheDataSource implements DataSource {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
source.close();
|
||||
cachedAuths.invalidateAll();
|
||||
executorService.shutdown();
|
||||
try {
|
||||
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
ConsoleLogger.writeStackTrace(e);
|
||||
ConsoleLogger.logException("Could not close executor service:", e);
|
||||
}
|
||||
cachedAuths.invalidateAll();
|
||||
source.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -190,8 +185,8 @@ public class CacheDataSource implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeBanned(final Set<String> banned) {
|
||||
source.purgeBanned(banned);
|
||||
public void purgeRecords(final Collection<String> banned) {
|
||||
source.purgeRecords(banned);
|
||||
cachedAuths.invalidateAll(banned);
|
||||
}
|
||||
|
||||
@ -235,15 +230,6 @@ public class CacheDataSource implements DataSource {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateIp(String user, String ip) {
|
||||
boolean result = source.updateIp(user, ip);
|
||||
if (result) {
|
||||
cachedAuths.refresh(user);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
return source.getAllAuths();
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fr.xephi.authme.datasource;
|
||||
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||
|
||||
/**
|
||||
@ -23,7 +23,7 @@ public final class Columns {
|
||||
public final String ID;
|
||||
public final String IS_LOGGED;
|
||||
|
||||
public Columns(NewSetting settings) {
|
||||
public Columns(Settings settings) {
|
||||
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
|
||||
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
|
||||
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.security.crypts.HashedPassword;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@ -70,13 +71,19 @@ public interface DataSource extends Reloadable {
|
||||
boolean updatePassword(String user, HashedPassword password);
|
||||
|
||||
/**
|
||||
* Purge all records in the database whose last login was longer ago than
|
||||
* the given time.
|
||||
* Get all records in the database whose last login was before the given time.
|
||||
*
|
||||
* @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.
|
||||
@ -123,13 +130,6 @@ public interface DataSource extends Reloadable {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -187,15 +187,6 @@ public interface DataSource extends Reloadable {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -1,12 +1,9 @@
|
||||
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.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
@ -17,6 +14,7 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -41,27 +39,11 @@ public class FlatFile implements DataSource {
|
||||
*/
|
||||
private final File source;
|
||||
|
||||
public FlatFile() {
|
||||
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) {
|
||||
public FlatFile(File source) throws IOException {
|
||||
this.source = source;
|
||||
if (!source.exists() && !source.createNewFile()) {
|
||||
throw new IOException("Could not create file '" + source.getPath() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +64,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -109,7 +91,7 @@ public class FlatFile implements DataSource {
|
||||
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");
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(bw);
|
||||
@ -145,7 +127,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -179,7 +161,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -216,7 +198,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -229,11 +211,10 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> autoPurgeDatabase(long until) {
|
||||
public Set<String> getRecordsToPurge(long until) {
|
||||
BufferedReader br = null;
|
||||
BufferedWriter bw = null;
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
Set<String> cleared = new HashSet<>();
|
||||
Set<String> list = new HashSet<>();
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(source));
|
||||
String line;
|
||||
@ -241,25 +222,24 @@ public class FlatFile implements DataSource {
|
||||
String[] args = line.split(":");
|
||||
if (args.length >= 4) {
|
||||
if (Long.parseLong(args[3]) >= until) {
|
||||
lines.add(line);
|
||||
list.add(args[0]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cleared.add(args[0]);
|
||||
}
|
||||
bw = new BufferedWriter(new FileWriter(source));
|
||||
for (String l : lines) {
|
||||
bw.write(l + "\n");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
return cleared;
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return list;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
silentClose(bw);
|
||||
}
|
||||
|
||||
return cleared;
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeRecords(Collection<String> toPurge) {
|
||||
throw new UnsupportedOperationException("Flat file no longer supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -284,7 +264,7 @@ public class FlatFile implements DataSource {
|
||||
bw.write(l + "\n");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -306,7 +286,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return null;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -339,10 +319,10 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
if (br != null) {
|
||||
@ -374,10 +354,10 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
return countIp;
|
||||
} catch (FileNotFoundException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return new ArrayList<>();
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return new ArrayList<>();
|
||||
} finally {
|
||||
if (br != null) {
|
||||
@ -404,7 +384,7 @@ public class FlatFile implements DataSource {
|
||||
}
|
||||
return countEmail;
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
@ -416,37 +396,6 @@ public class FlatFile implements DataSource {
|
||||
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
|
||||
public DataSourceType getType() {
|
||||
return DataSourceType.FILE;
|
||||
@ -479,7 +428,7 @@ public class FlatFile implements DataSource {
|
||||
result++;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return result;
|
||||
} finally {
|
||||
silentClose(br);
|
||||
@ -492,11 +441,6 @@ public class FlatFile implements DataSource {
|
||||
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
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
BufferedReader br = null;
|
||||
|
@ -3,13 +3,11 @@ package fr.xephi.authme.datasource;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.HashAlgorithm;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.security.crypts.XFBCRYPT;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
@ -25,72 +23,65 @@ import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class MySQL implements DataSource {
|
||||
|
||||
private final String host;
|
||||
private final String port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final String database;
|
||||
private final String tableName;
|
||||
private final List<String> columnOthers;
|
||||
private final Columns col;
|
||||
private final HashAlgorithm hashAlgorithm;
|
||||
private String host;
|
||||
private String port;
|
||||
private String username;
|
||||
private String password;
|
||||
private String database;
|
||||
private String tableName;
|
||||
private List<String> columnOthers;
|
||||
private Columns col;
|
||||
private HashAlgorithm hashAlgorithm;
|
||||
private HikariDataSource ds;
|
||||
|
||||
private final String phpBbPrefix;
|
||||
private final int phpBbGroup;
|
||||
private final String wordpressPrefix;
|
||||
private String phpBbPrefix;
|
||||
private int phpBbGroup;
|
||||
private String wordpressPrefix;
|
||||
|
||||
public MySQL(NewSetting settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
|
||||
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
|
||||
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);
|
||||
public MySQL(Settings settings) throws ClassNotFoundException, SQLException, PoolInitializationException {
|
||||
setParameters(settings);
|
||||
|
||||
// Set the connection arguments (and check if connection is ok)
|
||||
try {
|
||||
this.setConnectionArguments();
|
||||
} catch (RuntimeException e) {
|
||||
if (e instanceof IllegalArgumentException) {
|
||||
ConsoleLogger.showError("Invalid database arguments! Please check your configuration!");
|
||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
||||
throw new IllegalArgumentException(e);
|
||||
ConsoleLogger.warning("Invalid database arguments! Please check your configuration!");
|
||||
ConsoleLogger.warning("If this error persists, please report it to the developer!");
|
||||
}
|
||||
if (e instanceof PoolInitializationException) {
|
||||
ConsoleLogger.showError("Can't initialize database connection! Please check your configuration!");
|
||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
||||
throw new PoolInitializationException(e);
|
||||
ConsoleLogger.warning("Can't initialize database connection! Please check your configuration!");
|
||||
ConsoleLogger.warning("If this error persists, please report it to the developer!");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Initialize the database
|
||||
try {
|
||||
this.setupConnection();
|
||||
checkTablesAndColumns();
|
||||
} catch (SQLException e) {
|
||||
this.close();
|
||||
ConsoleLogger.showError("Can't initialize the MySQL database... Please check your database settings in the config.yml file! SHUTDOWN...");
|
||||
ConsoleLogger.showError("If this error persists, please report it to the developer!");
|
||||
close();
|
||||
ConsoleLogger.logException("Can't initialize the MySQL database:", e);
|
||||
ConsoleLogger.warning("Please check your database settings in the config.yml file!");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@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.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
|
||||
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.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
|
||||
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
|
||||
ds = hikariDataSource;
|
||||
}
|
||||
|
||||
private void setConnectionArguments() throws RuntimeException {
|
||||
@ -147,118 +137,83 @@ public class MySQL implements DataSource {
|
||||
return ds.getConnection();
|
||||
}
|
||||
|
||||
private void setupConnection() throws SQLException {
|
||||
try (Connection con = getConnection()) {
|
||||
Statement st = con.createStatement();
|
||||
DatabaseMetaData md = con.getMetaData();
|
||||
// Create table if not exists.
|
||||
private void checkTablesAndColumns() throws SQLException {
|
||||
try (Connection con = getConnection(); Statement st = con.createStatement()) {
|
||||
// Create table with ID column if it doesn't exist
|
||||
String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " ("
|
||||
+ col.ID + " INTEGER AUTO_INCREMENT,"
|
||||
+ col.NAME + " VARCHAR(255) NOT NULL UNIQUE,"
|
||||
+ col.REAL_NAME + " VARCHAR(255) NOT NULL,"
|
||||
+ 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 + ")"
|
||||
+ ");";
|
||||
+ col.ID + " MEDIUMINT(8) UNSIGNED AUTO_INCREMENT,"
|
||||
+ "PRIMARY KEY (" + col.ID + ")"
|
||||
+ ") CHARACTER SET = utf8;";
|
||||
st.executeUpdate(sql);
|
||||
|
||||
ResultSet rs = md.getColumns(null, null, tableName, col.NAME);
|
||||
if (!rs.next()) {
|
||||
DatabaseMetaData md = con.getMetaData();
|
||||
if (isColumnMissing(md, col.NAME)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.NAME + " VARCHAR(255) NOT NULL UNIQUE AFTER " + col.ID + ";");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.REAL_NAME);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.REAL_NAME)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.REAL_NAME + " VARCHAR(255) NOT NULL AFTER " + col.NAME + ";");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.PASSWORD);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.PASSWORD)) {
|
||||
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()) {
|
||||
if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
||||
}
|
||||
|
||||
if (isColumnMissing(md, col.IP)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
||||
}
|
||||
rs.close();
|
||||
+ " ADD COLUMN " + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
|
||||
}
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.IP);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.LAST_LOGIN)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;");
|
||||
} else {
|
||||
migrateLastLoginColumnToBigInt(con, rs);
|
||||
migrateLastLoginColumn(con, md);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.LASTLOC_X)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||
+ 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_Z + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LASTLOC_Y);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_X);
|
||||
if (rs.next()) {
|
||||
} else {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " MODIFY "
|
||||
+ col.LASTLOC_X + " 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';");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.LASTLOC_WORLD);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.LASTLOC_WORLD)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||
+ col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world' AFTER " + col.LASTLOC_Z);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.EMAIL);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.EMAIL)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||
+ col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com' AFTER " + col.LASTLOC_WORLD);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
rs = md.getColumns(null, null, tableName, col.IS_LOGGED);
|
||||
if (!rs.next()) {
|
||||
if (isColumnMissing(md, col.IS_LOGGED)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
|
||||
+ col.IS_LOGGED + " SMALLINT NOT NULL DEFAULT '0' AFTER " + col.EMAIL);
|
||||
}
|
||||
rs.close();
|
||||
|
||||
st.close();
|
||||
}
|
||||
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
|
||||
public boolean isAuthAvailable(String user) {
|
||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||
@ -613,21 +568,18 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> autoPurgeDatabase(long until) {
|
||||
public Set<String> getRecordsToPurge(long until) {
|
||||
Set<String> list = new HashSet<>();
|
||||
|
||||
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||
try (Connection con = getConnection();
|
||||
PreparedStatement selectPst = con.prepareStatement(select);
|
||||
PreparedStatement deletePst = con.prepareStatement(delete)) {
|
||||
PreparedStatement selectPst = con.prepareStatement(select)) {
|
||||
selectPst.setLong(1, until);
|
||||
try (ResultSet rs = selectPst.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
list.add(rs.getString(col.NAME));
|
||||
}
|
||||
}
|
||||
deletePst.setLong(1, until);
|
||||
deletePst.executeUpdate();
|
||||
} catch (SQLException ex) {
|
||||
logSqlException(ex);
|
||||
}
|
||||
@ -742,11 +694,11 @@ public class MySQL implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeBanned(Set<String> banned) {
|
||||
public void purgeRecords(Collection<String> toPurge) {
|
||||
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||
for (String name : banned) {
|
||||
pst.setString(1, name);
|
||||
for (String name : toPurge) {
|
||||
pst.setString(1, name.toLowerCase());
|
||||
pst.executeUpdate();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@ -839,20 +791,6 @@ public class MySQL implements DataSource {
|
||||
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
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
List<PlayerAuth> auths = new ArrayList<>();
|
||||
@ -933,14 +871,35 @@ 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 rs ResultSet containing meta data for the lastlogin column
|
||||
* @param con connection to the database
|
||||
* @param metaData lastlogin column meta data
|
||||
* @throws SQLException
|
||||
*/
|
||||
private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException {
|
||||
final int columnType = rs.getInt("DATA_TYPE");
|
||||
private void migrateLastLoginColumn(Connection con, DatabaseMetaData metaData) throws SQLException {
|
||||
final int columnType;
|
||||
try (ResultSet rs = metaData.getColumns(null, null, tableName, col.LAST_LOGIN)) {
|
||||
if (!rs.next()) {
|
||||
ConsoleLogger.warning("Could not get LAST_LOGIN meta data. This should never happen!");
|
||||
return;
|
||||
}
|
||||
columnType = rs.getInt("DATA_TYPE");
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
@ -957,7 +916,7 @@ public class MySQL implements DataSource {
|
||||
con.prepareStatement(sql).execute();
|
||||
|
||||
// Set values of lastlogin based on lastlogin_old
|
||||
sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s)",
|
||||
sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s) * 1000",
|
||||
tableName, col.LAST_LOGIN, lastLoginOld);
|
||||
con.prepareStatement(sql).execute();
|
||||
|
||||
@ -967,6 +926,27 @@ public class MySQL implements DataSource {
|
||||
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) {
|
||||
|
@ -1,26 +1,26 @@
|
||||
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.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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 {
|
||||
@ -38,7 +38,7 @@ public class SQLite implements DataSource {
|
||||
* @throws ClassNotFoundException if no driver could be found for the datasource
|
||||
* @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.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||
this.col = new Columns(settings);
|
||||
@ -53,7 +53,7 @@ public class SQLite implements DataSource {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SQLite(NewSetting settings, Connection connection) {
|
||||
SQLite(Settings settings, Connection connection) {
|
||||
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||
this.col = new Columns(settings);
|
||||
@ -70,67 +70,73 @@ public class SQLite implements DataSource {
|
||||
this.con = DriverManager.getConnection("jdbc:sqlite:plugins/AuthMe/" + database + ".db");
|
||||
}
|
||||
|
||||
private void setup() throws SQLException {
|
||||
Statement st = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
st = con.createStatement();
|
||||
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 + "));");
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.PASSWORD);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL;");
|
||||
@VisibleForTesting
|
||||
protected void setup() throws SQLException {
|
||||
try (Statement st = con.createStatement()) {
|
||||
// Note: cannot add unique fields later on in SQLite, so we add it on initialization
|
||||
st.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " ("
|
||||
+ col.ID + " INTEGER AUTO_INCREMENT, "
|
||||
+ col.NAME + " VARCHAR(255) NOT NULL UNIQUE, "
|
||||
+ "CONSTRAINT table_const_prim PRIMARY KEY (" + col.ID + "));");
|
||||
|
||||
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()) {
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.SALT);
|
||||
if (!rs.next()) {
|
||||
|
||||
if (isColumnMissing(md, col.PASSWORD)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.PASSWORD + " VARCHAR(255) NOT NULL DEFAULT '';");
|
||||
}
|
||||
|
||||
if (!col.SALT.isEmpty() && isColumnMissing(md, col.SALT)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
if (isColumnMissing(md, col.IP)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL DEFAULT '';");
|
||||
}
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.IP);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL;");
|
||||
|
||||
if (isColumnMissing(md, col.LAST_LOGIN)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;");
|
||||
}
|
||||
rs.close();
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.LAST_LOGIN);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP DEFAULT current_timestamp;");
|
||||
|
||||
if (isColumnMissing(md, col.LASTLOC_X)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X
|
||||
+ " 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.LASTLOC_X);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X + " 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';");
|
||||
|
||||
if (isColumnMissing(md, col.LASTLOC_WORLD)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
|
||||
}
|
||||
rs.close();
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.LASTLOC_WORLD);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_WORLD + " VARCHAR(255) NOT NULL DEFAULT 'world';");
|
||||
|
||||
if (isColumnMissing(md, col.EMAIL)) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName
|
||||
+ " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
|
||||
}
|
||||
rs.close();
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.EMAIL);
|
||||
if (!rs.next()) {
|
||||
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.EMAIL + " VARCHAR(255) DEFAULT 'your@email.com';");
|
||||
}
|
||||
rs.close();
|
||||
rs = con.getMetaData().getColumns(null, null, tableName, col.IS_LOGGED);
|
||||
if (!rs.next()) {
|
||||
|
||||
if (isColumnMissing(md, col.IS_LOGGED)) {
|
||||
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");
|
||||
}
|
||||
|
||||
private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
|
||||
try (ResultSet rs = metaData.getColumns(null, null, tableName, columnName)) {
|
||||
return !rs.next();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
close(con);
|
||||
@ -147,12 +153,12 @@ public class SQLite implements DataSource {
|
||||
PreparedStatement pst = null;
|
||||
ResultSet rs = null;
|
||||
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);
|
||||
rs = pst.executeQuery();
|
||||
return rs.next();
|
||||
} catch (SQLException ex) {
|
||||
ConsoleLogger.showError(ex.getMessage());
|
||||
ConsoleLogger.warning(ex.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
close(rs);
|
||||
@ -207,7 +213,7 @@ public class SQLite implements DataSource {
|
||||
HashedPassword password = auth.getPassword();
|
||||
if (col.SALT.isEmpty()) {
|
||||
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!");
|
||||
}
|
||||
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD +
|
||||
@ -293,20 +299,17 @@ public class SQLite implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> autoPurgeDatabase(long until) {
|
||||
public Set<String> getRecordsToPurge(long until) {
|
||||
Set<String> list = new HashSet<>();
|
||||
|
||||
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);
|
||||
PreparedStatement deletePst = con.prepareStatement(delete)) {
|
||||
try (PreparedStatement selectPst = con.prepareStatement(select)) {
|
||||
selectPst.setLong(1, until);
|
||||
try (ResultSet rs = selectPst.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
list.add(rs.getString(col.NAME));
|
||||
}
|
||||
}
|
||||
deletePst.setLong(1, until);
|
||||
deletePst.executeUpdate();
|
||||
} catch (SQLException ex) {
|
||||
logSqlException(ex);
|
||||
}
|
||||
@ -314,6 +317,19 @@ public class SQLite implements DataSource {
|
||||
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
|
||||
public boolean removeAuth(String user) {
|
||||
PreparedStatement pst = null;
|
||||
@ -443,19 +459,6 @@ public class SQLite implements DataSource {
|
||||
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
|
||||
public DataSourceType getType() {
|
||||
return DataSourceType.SQLITE;
|
||||
@ -553,20 +556,6 @@ public class SQLite implements DataSource {
|
||||
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
|
||||
public List<PlayerAuth> getAllAuths() {
|
||||
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.ByteStreams;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
public class BungeeCordMessage implements PluginMessageListener {
|
||||
|
||||
@Inject
|
||||
@ -28,9 +24,6 @@ public class BungeeCordMessage implements PluginMessageListener {
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private AuthMe plugin;
|
||||
|
||||
BungeeCordMessage() { }
|
||||
|
||||
|
||||
@ -56,26 +49,13 @@ public class BungeeCordMessage implements PluginMessageListener {
|
||||
if ("login".equals(act)) {
|
||||
playerCache.updatePlayer(auth);
|
||||
dataSource.setLogged(name);
|
||||
//START 03062016 sgdc3: should fix #731 but we need to recode this mess
|
||||
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!");
|
||||
}
|
||||
ConsoleLogger.fine("Player " + auth.getNickname() + " has logged in from one of your server!");
|
||||
} else if ("logout".equals(act)) {
|
||||
playerCache.removePlayer(name);
|
||||
dataSource.setUnlogged(name);
|
||||
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
|
||||
ConsoleLogger.info("Player " + auth.getNickname() + " has logged out from one of your server!");
|
||||
}
|
||||
ConsoleLogger.fine("Player " + auth.getNickname() + " has logged out from one of your server!");
|
||||
} else if ("register".equals(act)) {
|
||||
if (!plugin.getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
|
||||
ConsoleLogger.info("Player " + auth.getNickname() + " has registered out from one of your server!");
|
||||
}
|
||||
ConsoleLogger.fine("Player " + auth.getNickname() + " has registered out from one of your server!");
|
||||
} else if ("changepassword".equals(act)) {
|
||||
final String password = args[2];
|
||||
final String salt = args.length >= 4 ? args[3] : null;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.hooks;
|
||||
|
||||
import ch.jalu.injector.annotations.NoFieldScan;
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
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.
|
||||
*/
|
||||
@NoFieldScan
|
||||
public class PluginHooks {
|
||||
|
||||
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.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.PluginSettings;
|
||||
import org.mcstats.Metrics;
|
||||
@ -10,12 +10,12 @@ import org.mcstats.Metrics.Graph;
|
||||
|
||||
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 {
|
||||
final Metrics metrics = new Metrics(plugin);
|
||||
|
||||
@ -41,7 +41,7 @@ public class MetricsStarter {
|
||||
metrics.start();
|
||||
} catch (IOException e) {
|
||||
// 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;
|
||||
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.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 {
|
||||
|
||||
/**
|
||||
* Loads the needed settings.
|
||||
* Performs a reload with the provided 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;
|
||||
|
||||
public class AuthMeBlockListener implements Listener {
|
||||
public class BlockListener implements Listener {
|
||||
|
||||
@Inject
|
||||
private ListenerService listenerService;
|
@ -1,6 +1,7 @@
|
||||
package fr.xephi.authme.listener;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
@ -20,14 +21,14 @@ import javax.inject.Inject;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class AuthMeEntityListener implements Listener {
|
||||
public class EntityListener implements Listener {
|
||||
|
||||
private final ListenerService listenerService;
|
||||
private Method getShooter;
|
||||
private boolean shooterIsLivingEntity;
|
||||
|
||||
@Inject
|
||||
AuthMeEntityListener(ListenerService listenerService) {
|
||||
EntityListener(ListenerService listenerService) {
|
||||
this.listenerService = listenerService;
|
||||
try {
|
||||
getShooter = Projectile.class.getDeclaredMethod("getShooter");
|
||||
@ -39,7 +40,7 @@ public class AuthMeEntityListener implements Listener {
|
||||
|
||||
// Note #360: npc status can be used to bypass security!!!
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if (listenerService.shouldCancelEvent(event)) {
|
||||
event.getEntity().setFireTicks(0);
|
||||
event.setDamage(0);
|
||||
@ -48,16 +49,16 @@ public class AuthMeEntityListener implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onEntityTarget(EntityTargetEvent event) {
|
||||
if (listenerService.shouldCancelEvent(event)) {
|
||||
event.setTarget(null);
|
||||
public void onAttack(EntityDamageByEntityEvent event) {
|
||||
if (listenerService.shouldCancelEvent(event.getDamager())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onDamage(EntityDamageByEntityEvent event) {
|
||||
public void onEntityTarget(EntityTargetEvent event) {
|
||||
if (listenerService.shouldCancelEvent(event)) {
|
||||
event.setTarget(null);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@ import fr.xephi.authme.util.StringUtils;
|
||||
/**
|
||||
* Exception thrown when a verification has failed.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FailedVerificationException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 3903242223297960699L;
|
||||
private final MessageKey reason;
|
||||
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.hooks.PluginHooks;
|
||||
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.RestrictionSettings;
|
||||
import fr.xephi.authme.util.ValidationService;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityEvent;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
|
||||
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.
|
||||
@ -24,16 +22,18 @@ class ListenerService implements SettingsDependent {
|
||||
private final DataSource dataSource;
|
||||
private final PluginHooks pluginHooks;
|
||||
private final PlayerCache playerCache;
|
||||
private final ValidationService validationService;
|
||||
|
||||
private boolean isRegistrationForced;
|
||||
private Set<String> unrestrictedNames;
|
||||
|
||||
@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.pluginHooks = pluginHooks;
|
||||
this.playerCache = playerCache;
|
||||
loadSettings(settings);
|
||||
this.validationService = validationService;
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,10 +44,19 @@ class ListenerService implements SettingsDependent {
|
||||
*/
|
||||
public boolean shouldCancelEvent(EntityEvent event) {
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player player = (Player) entity;
|
||||
return shouldCancelEvent(player);
|
||||
}
|
||||
@ -74,10 +83,8 @@ class ListenerService implements SettingsDependent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings(NewSetting settings) {
|
||||
public void reload(Settings settings) {
|
||||
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
|
||||
*/
|
||||
private boolean checkAuth(String name) {
|
||||
if (isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
||||
if (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
||||
return true;
|
||||
}
|
||||
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
|
||||
@ -96,14 +103,4 @@ class ListenerService implements SettingsDependent {
|
||||
}
|
||||
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.permission.PermissionsManager;
|
||||
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.RegistrationSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import fr.xephi.authme.util.ValidationService;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -31,7 +32,7 @@ import java.util.regex.Pattern;
|
||||
class OnJoinVerifier implements Reloadable {
|
||||
|
||||
@Inject
|
||||
private NewSetting settings;
|
||||
private Settings settings;
|
||||
@Inject
|
||||
private DataSource dataSource;
|
||||
@Inject
|
||||
@ -56,13 +57,7 @@ class OnJoinVerifier implements Reloadable {
|
||||
@Override
|
||||
public void reload() {
|
||||
String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS);
|
||||
try {
|
||||
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");
|
||||
}
|
||||
nicknamePattern = Utils.safePatternCompile(nickRegEx);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +68,7 @@ class OnJoinVerifier implements Reloadable {
|
||||
*/
|
||||
public void checkAntibot(String playerName, boolean isAuthAvailable) throws FailedVerificationException {
|
||||
if (antiBot.getAntiBotStatus() == AntiBot.AntiBotStatus.ACTIVE && !isAuthAvailable) {
|
||||
antiBot.antibotKicked.addIfAbsent(playerName);
|
||||
antiBot.addPlayerKick(playerName);
|
||||
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 event the login event of the player
|
||||
* @param playerIp the ip address of the player
|
||||
*/
|
||||
public void checkPlayerCountry(boolean isAuthAvailable,
|
||||
PlayerLoginEvent event) throws FailedVerificationException {
|
||||
if (!isAuthAvailable && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
|
||||
String playerIp = event.getAddress().getHostAddress();
|
||||
String playerIp) throws FailedVerificationException {
|
||||
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
|
||||
&& settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)) {
|
||||
if (!validationService.isCountryAdmitted(playerIp)) {
|
||||
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.Messages;
|
||||
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.properties.HooksSettings;
|
||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
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.entity.Player;
|
||||
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.InventoryOpenEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
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.
|
||||
*/
|
||||
public class AuthMePlayerListener implements Listener {
|
||||
public class PlayerListener implements Listener {
|
||||
|
||||
public static final ConcurrentHashMap<String, String> joinMessage = new ConcurrentHashMap<>();
|
||||
|
||||
@Inject
|
||||
private NewSetting settings;
|
||||
private Settings settings;
|
||||
@Inject
|
||||
private Messages m;
|
||||
@Inject
|
||||
@ -73,6 +73,10 @@ public class AuthMePlayerListener implements Listener {
|
||||
private OnJoinVerifier onJoinVerifier;
|
||||
@Inject
|
||||
private ListenerService listenerService;
|
||||
@Inject
|
||||
private TeleportationService teleportationService;
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
|
||||
@ -141,10 +145,6 @@ public class AuthMePlayerListener implements Listener {
|
||||
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
|
||||
// "cancel" the event
|
||||
event.setTo(event.getFrom());
|
||||
if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
||||
player.setFlySpeed(0.0f);
|
||||
player.setWalkSpeed(0.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -189,47 +189,24 @@ public class AuthMePlayerListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player != null) {
|
||||
// Schedule login task so works after the prelogin
|
||||
// (Fix found by Koolaid5000)
|
||||
bukkitService.runTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
teleportationService.teleportNewPlayerToFirstSpawn(player);
|
||||
management.performJoin(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Note ljacqu 20160528: 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
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPreLogin(AsyncPlayerPreLoginEvent event) {
|
||||
final String name = event.getName().toLowerCase();
|
||||
final boolean isAuthAvailable = dataSource.isAuthAvailable(event.getName());
|
||||
// Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
|
||||
// e.g. CraftBukkit does not fire it. So we need to run crucial things with PlayerLoginEvent.
|
||||
// Single session feature can be implemented for Spigot and CraftBukkit by canceling a kick
|
||||
// event caused by "logged in from another location". The nicer way, but only for Spigot, would be
|
||||
// to check in the AsyncPlayerPreLoginEvent. To support all servers, we use the less nice way.
|
||||
|
||||
try {
|
||||
// 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)
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (Utils.isUnrestricted(player)) {
|
||||
final String name = player.getName();
|
||||
if (validationService.isUnrestricted(name)) {
|
||||
return;
|
||||
} else if (onJoinVerifier.refusePlayerForFullServer(event)) {
|
||||
return;
|
||||
@ -237,16 +214,20 @@ public class AuthMePlayerListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
final String name = player.getName().toLowerCase();
|
||||
final PlayerAuth auth = dataSource.getAuth(player.getName());
|
||||
final boolean isAuthAvailable = (auth != null);
|
||||
|
||||
try {
|
||||
onJoinVerifier.checkAntibot(name, isAuthAvailable);
|
||||
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
|
||||
// Fast stuff
|
||||
onJoinVerifier.checkSingleSession(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.checkPlayerCountry(isAuthAvailable, event);
|
||||
onJoinVerifier.checkPlayerCountry(isAuthAvailable, event.getAddress().getHostAddress());
|
||||
} catch (FailedVerificationException e) {
|
||||
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
|
||||
@ -254,6 +235,7 @@ public class AuthMePlayerListener implements Listener {
|
||||
}
|
||||
|
||||
antiBot.handlePlayerJoin(player);
|
||||
teleportationService.teleportOnJoin(player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
@ -262,21 +244,32 @@ public class AuthMePlayerListener implements Listener {
|
||||
|
||||
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
|
||||
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;
|
||||
}
|
||||
|
||||
management.performQuit(player, false);
|
||||
management.performQuit(player);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
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())) {
|
||||
management.performQuit(player, true);
|
||||
final Player player = event.getPlayer();
|
||||
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.
|
||||
*/
|
||||
public class AuthMePlayerListener16 implements Listener {
|
||||
public class PlayerListener16 implements Listener {
|
||||
|
||||
@Inject
|
||||
private ListenerService listenerService;
|
@ -10,7 +10,7 @@ import javax.inject.Inject;
|
||||
/**
|
||||
* Listener of player events for events introduced in Minecraft 1.8.
|
||||
*/
|
||||
public class AuthMePlayerListener18 implements Listener {
|
||||
public class PlayerListener18 implements Listener {
|
||||
|
||||
@Inject
|
||||
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;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.hooks.PluginHooks;
|
||||
import fr.xephi.authme.output.MessageKey;
|
||||
import fr.xephi.authme.output.Messages;
|
||||
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
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.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.ServerListPingEvent;
|
||||
|
||||
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
|
||||
private PluginHooks pluginHooks;
|
||||
@Inject
|
||||
private SpawnLoader spawnLoader;
|
||||
@Inject
|
||||
private ValidationService validationService;
|
||||
private ProtocolLibService protocolLibService;
|
||||
@Inject
|
||||
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)
|
||||
public void onPluginDisable(PluginDisableEvent event) {
|
||||
// Make sure the plugin instance isn't null
|
||||
@ -72,13 +49,9 @@ public class AuthMeServerListener implements Listener {
|
||||
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
||||
spawnLoader.unloadEssentialsSpawn();
|
||||
ConsoleLogger.info("EssentialsSpawn has been disabled: unhooking");
|
||||
}
|
||||
|
||||
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
|
||||
plugin.inventoryProtector = null;
|
||||
plugin.tablistHider = null;
|
||||
plugin.tabComplete = null;
|
||||
ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!");
|
||||
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
|
||||
protocolLibService.disable();
|
||||
ConsoleLogger.warning("ProtocolLib has been disabled, unhooking packet adapters!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,10 +75,8 @@ public class AuthMeServerListener implements Listener {
|
||||
pluginHooks.tryHookToCombatPlus();
|
||||
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
|
||||
spawnLoader.loadEssentialsSpawn();
|
||||
}
|
||||
|
||||
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
|
||||
plugin.checkProtocolLib();
|
||||
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
|
||||
protocolLibService.setup();
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.xephi.authme.listener;
|
||||
package fr.xephi.authme.listener.protocollib;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
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.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
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.entity.Player;
|
||||
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;
|
||||
|
||||
public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
||||
class InventoryPacketAdapter extends PacketAdapter {
|
||||
|
||||
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)
|
||||
@ -48,12 +40,8 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
||||
private static final int ARMOR_SIZE = 4;
|
||||
private static final int MAIN_SIZE = 27;
|
||||
private static final int HOTBAR_SIZE = 9;
|
||||
private static final int OFF_HAND_POSITION = 45;
|
||||
|
||||
private final boolean offHandSupported = MethodUtils
|
||||
.getAccessibleMethod(PlayerInventory.class, "getItemInOffHand", new Class[]{}) != null;
|
||||
|
||||
public AuthMeInventoryPacketAdapter(AuthMe plugin) {
|
||||
public InventoryPacketAdapter(AuthMe plugin) {
|
||||
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();
|
||||
|
||||
byte windowId = packet.getIntegers().read(0).byteValue();
|
||||
if (windowId == PLAYER_INVENTORY && Settings.protectInventoryBeforeLogInEnabled
|
||||
&& !PlayerCache.getInstance().isAuthenticated(player.getName())) {
|
||||
if (windowId == PLAYER_INVENTORY && !PlayerCache.getInstance().isAuthenticated(player.getName())) {
|
||||
packetEvent.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@ -77,52 +64,6 @@ public class AuthMeInventoryPacketAdapter extends PacketAdapter {
|
||||
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) {
|
||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
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.ProtocolLibrary;
|
||||
@ -6,17 +6,13 @@ import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerCache;
|
||||
|
||||
import javax.inject.Inject;
|
||||
class TabCompletePacketAdapter extends PacketAdapter {
|
||||
|
||||
public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
|
||||
|
||||
@Inject
|
||||
public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
|
||||
public TabCompletePacketAdapter(AuthMe plugin) {
|
||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
||||
}
|
||||
|
||||
@ -28,7 +24,7 @@ public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} 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.ConsoleLogger;
|
||||
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.util.BukkitService;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.apache.commons.mail.EmailConstants;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.mail.Session;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.Security;
|
||||
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
|
||||
*/
|
||||
public class SendMailSSL {
|
||||
|
||||
private final AuthMe plugin;
|
||||
private final NewSetting settings;
|
||||
@Inject
|
||||
private AuthMe plugin;
|
||||
@Inject
|
||||
private Settings settings;
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
|
||||
public SendMailSSL(AuthMe plugin, NewSetting settings) {
|
||||
this.plugin = plugin;
|
||||
this.settings = settings;
|
||||
SendMailSSL() {
|
||||
}
|
||||
|
||||
public void main(final PlayerAuth auth, final String newPass) {
|
||||
final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||
/**
|
||||
* Returns whether all necessary settings are set for sending mails.
|
||||
*
|
||||
* @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
|
||||
public void run() {
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
HtmlEmail email;
|
||||
try {
|
||||
email = initializeMail(auth, settings);
|
||||
email = initializeMail(auth.getEmail());
|
||||
} catch (EmailException e) {
|
||||
ConsoleLogger.logException("Failed to create email with the given settings:", e);
|
||||
return;
|
||||
@ -54,7 +81,7 @@ public class SendMailSSL {
|
||||
File file = null;
|
||||
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
|
||||
try {
|
||||
file = generateImage(auth, plugin, newPass);
|
||||
file = generateImage(auth.getNickname(), plugin, newPass);
|
||||
content = embedImageIntoEmailContent(file, email, content);
|
||||
} catch (IOException | EmailException e) {
|
||||
ConsoleLogger.logException(
|
||||
@ -67,13 +94,12 @@ public class SendMailSSL {
|
||||
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);
|
||||
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);
|
||||
return file;
|
||||
}
|
||||
@ -85,8 +111,7 @@ public class SendMailSSL {
|
||||
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
|
||||
}
|
||||
|
||||
private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings)
|
||||
throws EmailException {
|
||||
private HtmlEmail initializeMail(String emailAddress) throws EmailException {
|
||||
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
|
||||
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
|
||||
? senderMail
|
||||
@ -98,12 +123,12 @@ public class SendMailSSL {
|
||||
email.setCharset(EmailConstants.UTF_8);
|
||||
email.setSmtpPort(port);
|
||||
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
|
||||
email.addTo(auth.getEmail());
|
||||
email.addTo(emailAddress);
|
||||
email.setFrom(senderMail, senderName);
|
||||
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
|
||||
email.setAuthentication(senderMail, mailPassword);
|
||||
|
||||
setPropertiesForPort(email, port, settings);
|
||||
setPropertiesForPort(email, port);
|
||||
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
|
||||
.replace("<playername />", auth.getNickname())
|
||||
.replace("<servername />", plugin.getServer().getServerName())
|
||||
.replace("<generatedpass />", newPass);
|
||||
}
|
||||
|
||||
private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings)
|
||||
throws EmailException {
|
||||
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
|
||||
switch (port) {
|
||||
case 587:
|
||||
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.Marker;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.filter.AbstractFilter;
|
||||
import org.apache.logging.log4j.message.Message;
|
||||
|
||||
/**
|
||||
@ -12,7 +12,8 @@ import org.apache.logging.log4j.message.Message;
|
||||
*
|
||||
* @author Xephi59
|
||||
*/
|
||||
public class Log4JFilter implements Filter {
|
||||
@SuppressWarnings("serial")
|
||||
public class Log4JFilter extends AbstractFilter {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -50,42 +51,30 @@ public class Log4JFilter implements Filter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(LogEvent record) {
|
||||
if (record == null) {
|
||||
return Result.NEUTRAL;
|
||||
public Result filter(LogEvent event) {
|
||||
Message candidate = null;
|
||||
if(event != null) {
|
||||
candidate = event.getMessage();
|
||||
}
|
||||
return validateMessage(record.getMessage());
|
||||
return validateMessage(candidate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger arg0, Level arg1, Marker arg2, String message, Object... arg4) {
|
||||
if (message == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
return validateMessage(message);
|
||||
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
|
||||
return validateMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger arg0, Level arg1, Marker arg2, Object message, Throwable arg4) {
|
||||
if (message == null) {
|
||||
return Result.NEUTRAL;
|
||||
}
|
||||
return validateMessage(message.toString());
|
||||
public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
|
||||
return validateMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result filter(Logger arg0, Level arg1, Marker arg2, Message message, Throwable arg4) {
|
||||
return validateMessage(message);
|
||||
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
|
||||
String candidate = null;
|
||||
if(msg != null) {
|
||||
candidate = msg.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result getOnMatch() {
|
||||
return Result.NEUTRAL;
|
||||
return validateMessage(candidate);
|
||||
}
|
||||
|
||||
@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_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[] tags;
|
||||
|
@ -2,13 +2,13 @@ package fr.xephi.authme.output;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@ -18,6 +18,9 @@ import java.io.InputStreamReader;
|
||||
*/
|
||||
public class Messages implements SettingsDependent {
|
||||
|
||||
// Custom Authme tag replaced to new line
|
||||
private static final String NEWLINE_TAG = "%nl%";
|
||||
|
||||
private FileConfiguration configuration;
|
||||
private String fileName;
|
||||
private final String defaultFile;
|
||||
@ -26,12 +29,12 @@ public class Messages implements SettingsDependent {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param messageFile The messages file to use
|
||||
* @param defaultFile The file with messages to use as default if missing
|
||||
* @param settings The settings
|
||||
*/
|
||||
public Messages(File messageFile, String defaultFile) {
|
||||
initializeFile(messageFile);
|
||||
this.defaultFile = defaultFile;
|
||||
@Inject
|
||||
Messages(Settings settings) {
|
||||
reload(settings);
|
||||
this.defaultFile = settings.getDefaultMessagesFile();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,18 +73,12 @@ public class Messages implements SettingsDependent {
|
||||
* @return The message split by new lines
|
||||
*/
|
||||
public String[] retrieve(MessageKey key) {
|
||||
final String code = key.getKey();
|
||||
String message = configuration.getString(code);
|
||||
|
||||
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()) {
|
||||
String message = retrieveMessage(key);
|
||||
if (message.isEmpty()) {
|
||||
// Return empty array instead of array with 1 empty string as entry
|
||||
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
|
||||
* @return The message from the file
|
||||
*/
|
||||
public String retrieveSingle(MessageKey key) {
|
||||
return StringUtils.join("\n", retrieve(key));
|
||||
private String retrieveMessage(MessageKey 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
|
||||
*/
|
||||
public String retrieveSingle(MessageKey key, String... replacements) {
|
||||
String message = retrieveSingle(key);
|
||||
String message = retrieveMessage(key);
|
||||
String[] tags = key.getTags();
|
||||
if (replacements.length == tags.length) {
|
||||
for (int i = 0; i < tags.length; ++i) {
|
||||
message = message.replace(tags[i], replacements[i]);
|
||||
}
|
||||
} else {
|
||||
ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
|
||||
ConsoleLogger.warning("Invalid number of replacements for message key '" + key + "'");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings(NewSetting settings) {
|
||||
initializeFile(settings.getMessagesFile());
|
||||
}
|
||||
|
||||
private void initializeFile(File messageFile) {
|
||||
public void reload(Settings settings) {
|
||||
File messageFile = settings.getMessagesFile();
|
||||
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
|
||||
this.fileName = messageFile.getName();
|
||||
}
|
||||
@ -143,12 +145,9 @@ public class Messages implements SettingsDependent {
|
||||
return "Error retrieving message '" + code + "'";
|
||||
}
|
||||
|
||||
private static String[] formatMessage(String message) {
|
||||
String[] lines = message.split("&n");
|
||||
for (int i = 0; i < lines.length; ++i) {
|
||||
lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
|
||||
}
|
||||
return lines;
|
||||
private static String formatMessage(String message) {
|
||||
return ChatColor.translateAlternateColorCodes('&', message)
|
||||
.replace(NEWLINE_TAG, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,10 +2,12 @@ package fr.xephi.authme.permission;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.limbo.LimboCache;
|
||||
import fr.xephi.authme.cache.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.cache.limbo.PlayerData;
|
||||
import fr.xephi.authme.initialization.Reloadable;
|
||||
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.SecuritySettings;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
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.
|
||||
*/
|
||||
public class AuthGroupHandler {
|
||||
public class AuthGroupHandler implements Reloadable {
|
||||
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
|
||||
@Inject
|
||||
private NewSetting settings;
|
||||
private Settings settings;
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
|
||||
private String unloggedInGroup;
|
||||
private String unregisteredGroup;
|
||||
private String registeredGroup;
|
||||
|
||||
AuthGroupHandler() { }
|
||||
|
||||
/**
|
||||
@ -44,41 +50,74 @@ public class AuthGroupHandler {
|
||||
|
||||
// Make sure group support is available
|
||||
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;
|
||||
}
|
||||
|
||||
switch (group) {
|
||||
case UNREGISTERED:
|
||||
// Remove the other group type groups, set the current group
|
||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.getRegisteredGroup, Settings.getUnloggedinGroup));
|
||||
return permissionsManager.addGroup(player, Settings.unRegisteredGroup);
|
||||
permissionsManager.removeGroups(player, Arrays.asList(registeredGroup, unloggedInGroup));
|
||||
return permissionsManager.addGroup(player, unregisteredGroup);
|
||||
|
||||
case REGISTERED:
|
||||
// Remove the other group type groups, set the current group
|
||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getUnloggedinGroup));
|
||||
return permissionsManager.addGroup(player, Settings.getRegisteredGroup);
|
||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, unloggedInGroup));
|
||||
return permissionsManager.addGroup(player, registeredGroup);
|
||||
|
||||
case NOT_LOGGED_IN:
|
||||
// Remove the other group type groups, set the current group
|
||||
permissionsManager.removeGroups(player, Arrays.asList(Settings.unRegisteredGroup, Settings.getRegisteredGroup));
|
||||
return permissionsManager.addGroup(player, Settings.getUnloggedinGroup);
|
||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup));
|
||||
return permissionsManager.addGroup(player, unloggedInGroup);
|
||||
|
||||
case LOGGED_IN:
|
||||
// Get the limbo player data
|
||||
LimboPlayer limbo = limboCache.getLimboPlayer(player.getName().toLowerCase());
|
||||
if (limbo == null)
|
||||
// Get the player data
|
||||
PlayerData data = limboCache.getPlayerData(player.getName().toLowerCase());
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the players group
|
||||
String realGroup = limbo.getGroup();
|
||||
String realGroup = data.getGroup();
|
||||
|
||||
// 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);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This method requires better explanation.
|
||||
* <p>
|
||||
* Set the normal group of a player.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param group The normal group.
|
||||
*
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
public boolean addNormal(Player player, String group) {
|
||||
// Check whether the permissions check is enabled
|
||||
if (!settings.getProperty(PluginSettings.ENABLE_PERMISSION_CHECK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove old groups
|
||||
permissionsManager.removeGroups(player, Arrays.asList(unregisteredGroup, registeredGroup, unloggedInGroup));
|
||||
|
||||
// Add the normal group, return the result
|
||||
return permissionsManager.addGroup(player, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
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.
|
||||
@ -10,7 +10,7 @@ public enum DefaultPermission {
|
||||
/** No one has permission. */
|
||||
NOT_ALLOWED("No permission") {
|
||||
@Override
|
||||
public boolean evaluate(CommandSender sender) {
|
||||
public boolean evaluate(ServerOperator sender) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
@ -18,15 +18,15 @@ public enum DefaultPermission {
|
||||
/** Only players with OP status have permission. */
|
||||
OP_ONLY("OP's only") {
|
||||
@Override
|
||||
public boolean evaluate(CommandSender sender) {
|
||||
return sender.isOp();
|
||||
public boolean evaluate(ServerOperator sender) {
|
||||
return sender != null && sender.isOp();
|
||||
}
|
||||
},
|
||||
|
||||
/** Everyone is granted permission. */
|
||||
ALLOWED("Everyone allowed") {
|
||||
@Override
|
||||
public boolean evaluate(CommandSender sender) {
|
||||
public boolean evaluate(ServerOperator sender) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -48,7 +48,7 @@ public enum DefaultPermission {
|
||||
* @param sender the sender to process
|
||||
* @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.
|
||||
|
@ -1,25 +1,23 @@
|
||||
package fr.xephi.authme.permission;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.initialization.Reloadable;
|
||||
import fr.xephi.authme.permission.handlers.BPermissionsHandler;
|
||||
import fr.xephi.authme.permission.handlers.GroupManagerHandler;
|
||||
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.PermissionsExHandler;
|
||||
import fr.xephi.authme.permission.handlers.VaultHandler;
|
||||
import fr.xephi.authme.permission.handlers.ZPermissionsHandler;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
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.inject.Inject;
|
||||
@ -38,7 +36,7 @@ import java.util.List;
|
||||
* @author Tim Visée, http://timvisee.com
|
||||
* @version 0.3
|
||||
*/
|
||||
public class PermissionsManager {
|
||||
public class PermissionsManager implements Reloadable {
|
||||
|
||||
private final Server server;
|
||||
private final PluginManager pluginManager;
|
||||
@ -74,90 +72,17 @@ public class PermissionsManager {
|
||||
* Setup and hook into the permissions systems.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void setup() {
|
||||
// Force-unhook from current hooked permissions systems
|
||||
unhook();
|
||||
|
||||
private void setup() {
|
||||
// Loop through all the available permissions system types
|
||||
for (PermissionsSystemType type : PermissionsSystemType.values()) {
|
||||
// Try to find and hook the current plugin if available, print an error if failed
|
||||
try {
|
||||
// Try to find the plugin for the current permissions system
|
||||
Plugin plugin = pluginManager.getPlugin(type.getPluginName());
|
||||
|
||||
// Make sure a plugin with this name was found
|
||||
if (plugin == null)
|
||||
continue;
|
||||
|
||||
// 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
|
||||
PermissionHandler handler = getPermissionHandler(type);
|
||||
if (handler != null) {
|
||||
// Show a success message and return
|
||||
this.handler = handler;
|
||||
ConsoleLogger.info("Hooked into " + type.getName() + "!");
|
||||
|
||||
// Return the used permissions system type
|
||||
return;
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// An error occurred, show a warning message
|
||||
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!");
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
public void unhook() {
|
||||
private void unhook() {
|
||||
// Reset the current used permissions system
|
||||
this.handler = null;
|
||||
|
||||
@ -182,11 +139,12 @@ public class PermissionsManager {
|
||||
/**
|
||||
* Reload the permissions manager, and re-hook all permission plugins.
|
||||
*/
|
||||
@Override
|
||||
public void reload() {
|
||||
// Unhook all permission plugins
|
||||
unhook();
|
||||
|
||||
// Set up the permissions manager again, return the result
|
||||
// Set up the permissions manager again
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
|
@ -27,6 +27,11 @@ public class BPermissionsHandler implements PermissionHandler {
|
||||
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
|
||||
public boolean isInGroup(Player player, String 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());
|
||||
}
|
||||
|
||||
@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
|
||||
public boolean isInGroup(Player player, String group) {
|
||||
final AnjoPermissionsHandler handler = groupManager.getWorldsHolder().getWorldPermissions(player);
|
||||
|
@ -38,6 +38,17 @@ public interface PermissionHandler {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(Player player, String group) {
|
||||
List<String> groupNames = getGroups(player);
|
||||
|
@ -1,6 +1,5 @@
|
||||
package fr.xephi.authme.permission.handlers;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -15,14 +14,16 @@ public class PermissionsExHandler implements PermissionHandler {
|
||||
|
||||
private PermissionManager permissionManager;
|
||||
|
||||
public PermissionsExHandler(PermissionManager permissionManager) {
|
||||
this.permissionManager = permissionManager;
|
||||
public PermissionsExHandler() throws PermissionHandlerException {
|
||||
permissionManager = PermissionsEx.getPermissionManager();
|
||||
if (permissionManager == null) {
|
||||
throw new PermissionHandlerException("Could not get manager of PermissionsEx");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addToGroup(Player player, String 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;
|
||||
}
|
||||
|
||||
@ -42,6 +43,12 @@ public class PermissionsExHandler implements PermissionHandler {
|
||||
return user.has(node.getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||
PermissionUser user = permissionManager.getUser(name);
|
||||
return user.has(node.getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(Player player, String group) {
|
||||
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.PermissionsSystemType;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -12,8 +14,24 @@ public class VaultHandler implements PermissionHandler {
|
||||
|
||||
private Permission vaultProvider;
|
||||
|
||||
public VaultHandler(Permission vaultProvider) {
|
||||
this.vaultProvider = vaultProvider;
|
||||
public VaultHandler(Server server) throws PermissionHandlerException {
|
||||
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
|
||||
@ -31,6 +49,11 @@ public class VaultHandler implements PermissionHandler {
|
||||
return vaultProvider.has(player, node.getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||
return vaultProvider.has("", name, node.getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(Player player, String group) {
|
||||
return vaultProvider.playerInGroup(player, group);
|
||||
|
@ -14,7 +14,12 @@ public class ZPermissionsHandler implements PermissionHandler {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -37,6 +42,15 @@ public class ZPermissionsHandler implements PermissionHandler {
|
||||
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
|
||||
public boolean isInGroup(Player player, String 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.unregister.AsynchronousUnregister;
|
||||
import fr.xephi.authme.util.BukkitService;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
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() {
|
||||
@Override
|
||||
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() {
|
||||
@Override
|
||||
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…
Reference in New Issue
Block a user