Compare commits

..

45 Commits

Author SHA1 Message Date
games647
6fd1e5e79c Fix TCPShield compat by using raw address for sessions
TCPShield overwrites the IP address during connection. ProtocolLib
doesn't notice this change, because it uses the end-to-end connection
which is the proxy IP. This causes getAddress calls during Spigot play
state and ProtocolLib auth state not match and then have conflicting
session ids.

A solution is also to hold onto the temporary player object. However
since we don't get a notification for a disconnect, holding it will
prevent to get GCed until the timeout occurs (1 minute).

Fixes #595
2021-08-14 21:01:56 +02:00
games647
213bacfab9 Add extra session logging 2021-08-14 17:05:27 +02:00
games647
232e9ac137 Use the address field for verify task 2021-08-14 17:05:18 +02:00
games647
f8fe3d7d71 Do not silence exceptions for Floodgate 2021-08-12 20:39:14 +02:00
games647
4d4ecf3da7 Merge pull request #583 from games647/dependabot/maven/org.slf4j-slf4j-jdk14-1.7.32
Bump slf4j-jdk14 from 1.7.31 to 1.7.32
2021-07-26 10:06:59 +02:00
dependabot[bot]
f80059987b Bump slf4j-jdk14 from 1.7.31 to 1.7.32
Bumps [slf4j-jdk14](https://github.com/qos-ch/slf4j) from 1.7.31 to 1.7.32.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/commits)

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-jdk14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-26 07:02:17 +00:00
games647
6e0272d92c Fix receiving login packet twice with ProtocolLib
Fixes #578
Commit that introduces the bug:
1f4757669c
2021-07-16 14:24:17 +02:00
games647
758ccb9bf2 Clean up 2021-07-14 16:33:31 +02:00
games647
0515ac193d Extract protocollib method detection 2021-07-14 16:33:18 +02:00
games647
864e551a88 Disable verbose verification output
NameChange fix is resolved
2021-07-14 16:32:32 +02:00
games647
0a24d36ef8 [ci skip] Rephrase development build section
Fixes #576
2021-07-12 17:25:52 +02:00
games647
8a535e1ad9 [ci skip] Merge pull request #574 from MAX-XiaoKui/patch-1
Update plugin SodionAuth's link. Its URL has changed.
2021-07-10 17:18:08 +02:00
MAX_小葵
ae66f1ab35 Update plugin SodionAuth's link 2021-07-10 22:04:54 +08:00
games647
ed725d991e [ci skip] Show user clickable links 2021-07-06 11:25:52 +02:00
games647
e45d4b3482 [ci skip] Require what happened form 2021-07-06 11:20:36 +02:00
games647
b5b5faaefb [ci skip] Add feedback message to forms 2021-06-30 17:23:54 +02:00
games647
51a28ae93f [CI-SKIP] Fix issue template syntax 2021-06-30 17:04:16 +02:00
games647
d2fcdade0b [CI-SKIP] Try out issue forms 2021-06-30 17:02:19 +02:00
games647
cde045d6fd Only build for main branches to fix duplicate actions with dependabot 2021-06-29 12:55:37 +02:00
games647
ccdc455ce9 Clarify naming and structure 2021-06-22 14:07:47 +02:00
games647
4e1f5e9401 Add icons to issue templates 2021-06-22 13:25:57 +02:00
games647
2e64b52261 Migrate questions to discussions 2021-06-22 13:25:41 +02:00
games647
1f4757669c Allow packet modifications by other plugins
If we disable filters, other plugins are advised to only monitor
packets. Potential modifications can be allowed by enabling the filtering again, but adding our meta data to prevent duplicate
processing.
2021-06-22 11:15:21 +02:00
games647
496817afca Increase the rate limit for bigger servers
Related #406
2021-06-21 18:00:45 +02:00
games647
daf6f06a00 Name anti-bot feature explicitly for own rate limiting 2021-06-21 17:33:38 +02:00
games647
4be0e1333d [CI-SKIP] Add issue template descriptions 2021-06-21 17:08:20 +02:00
games647
58cee1e26e Exclude more transitive dependencies
This could reduce the number of required
downloads as well as to prevent download
from legacy HTTP non secure (not HTTPS)
sources.
2021-06-21 17:08:20 +02:00
games647
9f89756820 Disable plugin if dependencies not available
Related #554
2021-06-21 17:08:20 +02:00
games647
d1daec436c Merge pull request #559 from Smart123s/fg2-ln-autoreg
Add 'linked' option to 'autoRegisterFloodgate'
2021-06-21 16:31:25 +02:00
Smart123s
2626c21bc8 Add 'linked' option to 'autoRegisterFloodgate'
This makes sense with Floodgate 2.0's Global Link API
2021-06-21 15:15:18 +02:00
games647
5607a19312 Merge pull request #560 from Smart123s/fg-player-to-account
Update messages
2021-06-21 14:30:46 +02:00
games647
1f950397a4 Merge pull request #561 from games647/dependabot/maven/org.slf4j-slf4j-jdk14-1.7.31
Bump slf4j-jdk14 from 1.7.30 to 1.7.31
2021-06-21 12:07:45 +02:00
dependabot[bot]
08e26dd60f Bump slf4j-jdk14 from 1.7.30 to 1.7.31
Bumps [slf4j-jdk14](https://github.com/qos-ch/slf4j) from 1.7.30 to 1.7.31.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/commits)

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-jdk14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-21 07:03:13 +00:00
Smart123s
2ffe7e0daf Replace word 'Player' with 'Account' in messages.
Technically speaking, one player can own both the Java and the Bedrock
account with the same name, so it's more appropriate to say account
instead of player.
2021-06-20 17:44:46 +02:00
Smart123s
33261b9ea6 Floodgate 2.0 is no longer in a seperate branch 2021-06-20 17:37:18 +02:00
games647
5442f773ae Merge pull request #558 from Smart123s/fg-sharedtask
Add Floodgate config options for BungeeCord
2021-06-20 14:03:45 +02:00
Smart123s
fd3da28bec Use Override for non core code in FloodgateAuthTas 2021-06-20 13:35:31 +02:00
Smart123s
9350f52916 Create a seperate function for isNameCheckRequired 2021-06-20 13:23:51 +02:00
Smart123s
7c2bb9c9a4 Don't spam log when with unregistered floodgate 2021-06-20 13:05:04 +02:00
Smart123s
0b307a95a3 Add further documentation to config.yml
Floodgate options are no longer Bukkit only
autoRegister/LoginFloodgate needs normal (Java) autoRegister/Login
to be set to ture
2021-06-20 11:26:15 +02:00
Smart123s
ed627ce438 Add autoLogin and register for Floodgate Bungee 2021-06-20 11:26:14 +02:00
Smart123s
af83604c94 Remove existing Floodgate integration from Bungee 2021-06-20 11:26:13 +02:00
Smart123s
8f43cc0978 Partially move FloodgateAuthTask to Core
The moved code can be used in a BungeeCord implementation
2021-06-20 11:26:13 +02:00
games647
578028719f Merge pull request #556 from Smart123s/patch-5
FloodgateNameConflict no longer needs autoLogin
2021-06-19 10:43:09 +02:00
Péter Tombor
b87b59be12 FloodgateNameConflict no longer needs autoLogin
The removed line is not valid after 1f3cd5fa5b
2021-06-18 23:25:46 +02:00
35 changed files with 577 additions and 366 deletions

View File

@@ -1,41 +0,0 @@
---
name: Bug report
about: Something isn't working
title: ''
labels: 'bug'
assignees: ''
---
[//]: # (Lines in this format are considered as comments and will not be displayed.)
[//]: # (Before reporting make sure you're running the **latest build** of the plugin and checked for existing issues!)
### What behaviour is observed:
[//]: # (What happened?)
### What behaviour is expected:
[//]: # (What did you expect?)
### Steps/models to reproduce:
[//]: # (The actions that cause the issue. Please explain it in detail)
### Screenshots (if applicable)
[//]: # (You can drop the files here directly)
### Plugin list:
[//]: # (This can be found by running `/pl`)
### Environment description
[//]: # (Server software with exact version number, Minecraft version, SQLite/MySQL/MariaDB, ...)
### Plugin version or build number (don't write latest):
[//]: # (This can be found by running `/version plugin-name`.)
### Server Log:
[//]: # (No images please - only the textual representation)
[Hastebin](https://hastebin.com/) / [Gist](https://gist.github.com/) link of the error, stacktrace or the complete log (if any)
### Configuration:
[//]: # (No images please - only the textual representation)
[//]: # (remember to delete any sensitive data)
[Hastebin](https://hastebin.com/) / [Gist](https://gist.github.com/) link of your config.yml file

67
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: 🐞 Bug Report
description: Something isn't working, broken, not expected behavior
labels: [bug]
body:
- type: markdown
attributes:
value: |
This ticket is about bugs, so broken, not expected behavior. Feedback about this form is appreciated.
- type: textarea
attributes:
label: What happened?
description: What behavior is observed?
validations:
required: true
- type: textarea
attributes:
label: What did you expect?
description: What behavior is expected?
- type: textarea
attributes:
label: Steps to reproduce
description: The actions that cause the issues. Please explain it in detail.
- type: input
attributes:
label: Plugin list
description: This can be found by running `/pl`
placeholder: AuthMe, ProtocolLib, ...
- type: input
attributes:
label: Configuration file
description: |
Link to the contents of your config.yml file.
You can use [GitHub](https://gist.github.com/), [Hastebin](https://hastebin.com) or similar for that.
placeholder: https://gist.github.com/games647/88c4439e1cd7810f21318b1b24a04ee0
- type: textarea
attributes:
label: Server log
description: The error, stacktrace or link the complete log. You can use the links above for long versions.
render: shell
placeholder: https://hastebin.com/ / https://gist.github.com/
- type: input
attributes:
label: Plugin version
description: Plugin version or build number. This can be found by running `/version plugin-name`
placeholder: v3.1-SNAPSHOT-570b321
validations:
required: true
- type: dropdown
attributes:
label: Platform
description:
options:
- Spigot
- BungeeCord
validations:
required: true
- type: checkboxes
attributes:
label: Relevance
description:
options:
- label: I tried the latest build
required: true
- label: |
I checked for existing tickets -
If there are, please vote them with a thumps reaction and not create new ones
required: true

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# General configuration for issue templates
# Allow issues without a template
#blank_issues_enabled: false
# Extra section on creating issues to redirect to another site
contact_links:
- name: 📌 Questions
url: https://github.com/games647/FastLogin/discussions
about: You want to ask something

View File

@@ -1,5 +1,5 @@
---
name: Enhancement request
name: 💡 Enhancement request
about: New feature or change request
title: ''
labels: 'enhancement'
@@ -8,6 +8,9 @@ assignees: ''
---
[//]: # (Lines in this format are considered as comments and will not be displayed.)
[//]: # (Before reporting make sure you're running the **latest build** of the plugin and checked for existing issues!)
[//]: # (This ticket is about suggestions for a feature or particular enhancement)
### Is your feature request related to a problem? Please describe.
[//]: # (A clear and concise description of what the problem is. Ex. I'm always frustrated when [...])

View File

@@ -1,10 +0,0 @@
---
name: Question
about: You want to ask something
title: ''
labels: 'question'
assignees: ''
---

View File

@@ -4,11 +4,15 @@
# Human readable name in the actions tab
name: Java CI
# Build on every push and pull request regardless of the branch
# Build on every pull request regardless of the branch
# Wiki: https://help.github.com/en/actions/reference/events-that-trigger-workflows
on:
- push
- pull_request
push:
branches:
- main
pull_request:
branches:
- main
jobs:
# job id
@@ -19,32 +23,32 @@ jobs:
# Run steps
steps:
# Pull changes
- uses: actions/checkout@v2.3.4
# Pull changes
- uses: actions/checkout@v2.3.4
# Cache artifacts - however this has the downside that we don't get notified of
# artifact resolution failures like invalid repository
# Nevertheless the repositories should be more stable and it makes no sense to pull
# a same version every time
# A dry run would make more sense
- uses: actions/cache@v2.1.4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# Cache artifacts - however this has the downside that we don't get notified of
# artifact resolution failures like invalid repository
# Nevertheless the repositories should be more stable and it makes no sense to pull
# a same version every time
# A dry run would make more sense
- uses: actions/cache@v2.1.4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# Setup Java
- name: Set up JDK
uses: actions/setup-java@v2.1.0
with:
distribution: 'adopt'
# Use Java 11, because it's minimum required version
java-version: 11
# Setup Java
- name: Set up JDK
uses: actions/setup-java@v2.1.0
with:
distribution: 'adopt'
# Use Java 11, because it's minimum required version
java-version: 11
# Build and test (included in package)
- name: Build with Maven and test
# Run non-interactive, package (with compile+test),
# ignore snapshot updates, because they are likely to have breaking changes, enforce checksums to validate
# possible errors in dependencies
run: mvn test --batch-mode --no-snapshot-updates --strict-checksums --file pom.xml
# Build and test (included in package)
- name: Build with Maven and test
# Run non-interactive, package (with compile+test),
# ignore snapshot updates, because they are likely to have breaking changes, enforce checksums to validate
# possible errors in dependencies
run: mvn test --batch-mode --no-snapshot-updates --strict-checksums --file pom.xml

View File

@@ -29,15 +29,11 @@ are still allowed and it could be re-opened.
## Development builds
Development builds of this project can be acquired at the provided CI (continuous integration) server. It contains the
latest changes from the Source-Code in preparation for the following release. This means they could contain new
features, bug fixes and other changes since the last release.
Development builds contain the latest changes from the Source-Code. They are bleeding edge and could introduce new bugs,
but also include features, enhancements and bug fixes that are not yet in a released version. If you click on the left
side on `Changes`, you can see iterative change sets leading to a specific build.
They **could** contain new bugs and are likely to be less stable than released versions.
Specific builds can be grabbed by clicking on the build number on the left side or by clicking on status to retrieve the
latest build.
https://ci.codemc.org/job/Games647/job/FastLogin/changes
You can download them from here: https://ci.codemc.org/job/Games647/job/FastLogin/
***
@@ -81,7 +77,7 @@ Possible values: `Premium`, `Cracked`, `Unknown`
* [CrazyLogin](https://dev.bukkit.org/bukkit-plugins/crazylogin/)
* [LoginSecurity](https://dev.bukkit.org/bukkit-plugins/loginsecurity/)
* [LogIt](https://github.com/games647/LogIt)
* [SodionAuth (2.0+)](https://github.com/Mohist-Community/SodionAuth)
* [SodionAuth (2.0+)](https://github.com/MohistMC/SodionAuth)
* [UltraAuth](https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/)
* [UserLogin](https://www.spigotmc.org/resources/userlogin.80669/)
* [xAuth](https://dev.bukkit.org/bukkit-plugins/xauth/)
@@ -90,7 +86,7 @@ Possible values: `Premium`, `Cracked`, `Unknown`
* [BungeeAuth](https://www.spigotmc.org/resources/bungeeauth.493/)
* [BungeeAuthenticator](https://www.spigotmc.org/resources/bungeecordauthenticator.87669/)
* [SodionAuth (2.0+)](https://github.com/Mohist-Community/SodionAuth)
* [SodionAuth (2.0+)](https://github.com/MohistMC/SodionAuth)
## Network requests

View File

@@ -145,7 +145,7 @@
<dependency>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -163,6 +163,12 @@
<artifactId>ProtocolLib</artifactId>
<version>4.6.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Changing onlinemode on login process-->
@@ -172,6 +178,12 @@
<!--4.29.dev after commit about API improvements-->
<version>3a80c661fe</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Provide premium placeholders-->

View File

@@ -25,10 +25,11 @@
*/
package com.github.games647.fastlogin.bukkit;
import com.destroystokyo.paper.event.player.PlayerHandshakeEvent;
import com.github.games647.fastlogin.bukkit.command.CrackedCommand;
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
import com.github.games647.fastlogin.bukkit.listener.PaperPreLoginListener;
import com.github.games647.fastlogin.bukkit.listener.PaperCacheListener;
import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener;
import com.github.games647.fastlogin.bukkit.listener.protocollib.SkinApplyListener;
import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener;
@@ -42,6 +43,7 @@ import io.papermc.lib.PaperLib;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -50,6 +52,8 @@ import java.util.concurrent.ConcurrentMap;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.slf4j.Logger;
@@ -63,10 +67,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(1, -1);
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
private final Logger logger;
private final BukkitScheduler scheduler;
private boolean serverStarted;
private BungeeManager bungeeManager;
private final BukkitScheduler scheduler;
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;
private PremiumPlaceholder premiumPlaceholder;
@@ -87,17 +90,26 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
setEnabled(false);
return;
}
// Check Floodgate config values
if (!isValidFloodgateConfigString("autoLoginFloodgate")
|| !isValidFloodgateConfigString("allowFloodgateNameConflict")) {
setEnabled(false);
return;
}
// Check Floodgate config values
if (!isValidFloodgateConfigString("autoLoginFloodgate")
|| !isValidFloodgateConfigString("allowFloodgateNameConflict")) {
setEnabled(false);
return;
}
bungeeManager = new BungeeManager(this);
bungeeManager.initialize();
getServer().getPluginManager().registerEvents(new Listener() {
@EventHandler
void onHandshake(PlayerHandshakeEvent handshakeEvent) {
handshakeEvent.setCancelled(false);
handshakeEvent.setSocketAddressHostname("192.168.0.1");
}
}, this);
PluginManager pluginManager = getServer().getPluginManager();
if (bungeeManager.isEnabled()) {
markInitialized();
@@ -118,6 +130,8 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
}
} else {
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
setEnabled(false);
return;
}
}
@@ -128,7 +142,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
//if server is using paper - we need to add one more listener to correct the usercache usage
if (PaperLib.isPaper()) {
pluginManager.registerEvents(new PaperPreLoginListener(this), this);
pluginManager.registerEvents(new PaperCacheListener(this), this);
}
//register commands using a unique name
@@ -178,7 +192,8 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
public BukkitLoginSession getSession(InetSocketAddress addr) {
String id = getSessionId(addr);
return loginSession.get(id);
BukkitLoginSession session = loginSession.get(id);
return session;
}
public String getSessionId(InetSocketAddress addr) {
@@ -247,60 +262,61 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
public void sendMessage(CommandSender receiver, String message) {
receiver.sendMessage(message);
}
/**
* Checks if a config entry (related to Floodgate) is valid. <br>
* Writes to Log if the value is invalid.
* <p>
* This should be used for:
* <ul>
* <li>allowFloodgateNameConflict
* <li>autoLoginFloodgate
* <li>autoRegisterFloodgate
* </ul>
* </p>
*
* @param key the key of the entry in config.yml
* @return <b>true</b> if the entry's value is "true", "false", or "linked"
*/
private boolean isValidFloodgateConfigString(String key) {
String value = core.getConfig().get(key).toString().toLowerCase();
if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) {
logger.error("Invalid value detected for {} in FastLogin/config.yml.", key);
return false;
}
return true;
}
/**
* Checks if a plugin is installed on the server
* @param name the name of the plugin
* @return true if the plugin is installed
*/
public boolean isPluginInstalled(String name) {
//the plugin may be enabled after FastLogin, so isPluginEnabled()
//won't work here
return Bukkit.getServer().getPluginManager().getPlugin(name) != null;
}
/**
* Send warning messages to log if incompatible plugins are used
* Checks if a config entry (related to Floodgate) is valid. <br>
* Writes to Log if the value is invalid.
* <p>
* This should be used for:
* <ul>
* <li>allowFloodgateNameConflict
* <li>autoLoginFloodgate
* <li>autoRegisterFloodgate
* </ul>
* </p>
*
* @param key the key of the entry in config.yml
* @return <b>true</b> if the entry's value is "true", "false", or "linked"
*/
private boolean isValidFloodgateConfigString(String key) {
String value = core.getConfig().get(key).toString().toLowerCase(Locale.ENGLISH);
if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) {
logger.error("Invalid value detected for {} in FastLogin/config.yml.", key);
return false;
}
return true;
}
/**
* Checks if a plugin is installed on the server
*
* @param name the name of the plugin
* @return true if the plugin is installed
*/
@Override
public boolean isPluginInstalled(String name) {
// the plugin may be enabled after FastLogin, so isPluginEnabled() won't work here
return Bukkit.getServer().getPluginManager().getPlugin(name) != null;
}
/**
* Send warning messages to log if incompatible plugins are used
*/
private void dependencyWarnings() {
if (isPluginInstalled("floodgate-bukkit")) {
logger.warn("We have detected that you are runnging Floodgate 1.0 which is not supported by the Bukkit "
logger.warn("We have detected that you are running Floodgate 1.0 which is not supported by the Bukkit "
+ "version of FastLogin.");
logger.warn("If you would like to use FastLogin with Floodgate, you can download developement builds of "
logger.warn("If you would like to use FastLogin with Floodgate, you can download development builds of "
+ "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/");
logger.warn("Don't forget to update Geyser to a supported version as well from "
+ "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/");
} else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
logger.warn("We have detected that you are runnging FastLogin alongside Floodgate and ProtocolLib.");
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from showing up "
+ "when it is together used with ProtocolLib.");
logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with ProtocolSupport "
+ "which does not have this issue.");
} else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib.");
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate's name prefixes from " +
"showing up when it is together used with ProtocolLib.");
logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with " +
"ProtocolSupport which does not have this issue.");
logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
}
}
}
}

View File

@@ -28,18 +28,20 @@ package com.github.games647.fastlogin.bukkit.hook;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import fr.xephi.authme.api.v3.AuthMeApi;
import fr.xephi.authme.events.RestoreSessionEvent;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams;
import fr.xephi.authme.process.register.executors.RegistrationMethod;
import java.lang.reflect.Field;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.lang.reflect.Field;
/**
* GitHub: https://github.com/Xephi/AuthMeReloaded/
* <p>
@@ -75,7 +77,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) {
Player player = restoreSessionEvent.getPlayer();
BukkitLoginSession session = plugin.getSession(player.getAddress());
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
if (session != null && session.isVerified()) {
restoreSessionEvent.setCancelled(true);
}

View File

@@ -126,7 +126,7 @@ public class BungeeListener implements PluginMessageListener {
private void startLoginTaskIfReady(Player player, BukkitLoginSession session) {
session.setVerified(true);
plugin.putSession(player.getAddress(), session);
plugin.putSession(player.spigot().getRawAddress(), session);
// only start a new login task if the join event fired earlier. This event then didn
boolean result = plugin.getBungeeManager().didJoinEventFired(player);

View File

@@ -72,21 +72,21 @@ public class ConnectionListener implements Listener {
// session exists so the player is ready for force login
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
// having the login session from the login process
BukkitLoginSession session = plugin.getSession(player.getAddress());
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
boolean isFloodgateLogin = false;
if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
FloodgatePlayer floodgatePlayer = FloodgateApi.getInstance().getPlayer(player.getUniqueId());
if (floodgatePlayer != null) {
isFloodgateLogin = true;
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin, player, floodgatePlayer);
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer);
Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
}
}
if (!isFloodgateLogin) {
if (session == null) {
String sessionId = plugin.getSessionId(player.getAddress());
String sessionId = plugin.getSessionId(player.spigot().getRawAddress());
plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId);
} else {
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);

View File

@@ -35,11 +35,11 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result;
public class PaperPreLoginListener implements Listener {
public class PaperCacheListener implements Listener {
private final FastLoginBukkit plugin;
public PaperPreLoginListener(final FastLoginBukkit plugin) {
public PaperCacheListener(final FastLoginBukkit plugin) {
this.plugin = plugin;
}

View File

@@ -52,9 +52,8 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
private final Player player;
private final String username;
public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random,
Player player, String username, PublicKey publicKey) {
public NameCheckTask(FastLoginBukkit plugin, Random random, Player player, PacketEvent packetEvent,
String username, PublicKey publicKey) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
this.plugin = plugin;
@@ -68,14 +67,15 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override
public void run() {
try {
super.onLogin(username, new ProtocolLibLoginSource(packetEvent, player, random, publicKey));
super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey));
} finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
}
@Override
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLibLoginSource source, StoredProfile profile) {
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLibLoginSource source,
StoredProfile profile) {
BukkitFastLoginPreLoginEvent event = new BukkitFastLoginPreLoginEvent(username, source, profile);
plugin.getServer().getPluginManager().callEvent(event);
return event;
@@ -87,7 +87,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
public void requestPremiumLogin(ProtocolLibLoginSource source, StoredProfile profile
, String username, boolean registered) {
try {
source.setOnlineMode();
source.enableOnlinemode();
} catch (Exception ex) {
plugin.getLog().error("Cannot send encryption packet. Falling back to cracked login for: {}", profile, ex);
return;

View File

@@ -43,6 +43,8 @@ import static com.comphenix.protocol.PacketType.Login.Client.START;
public class ProtocolLibListener extends PacketAdapter {
public static final String SOURCE_META_KEY = "source";
private final FastLoginBukkit plugin;
//just create a new once on plugin enable. This used for verify token generation
@@ -62,7 +64,8 @@ public class ProtocolLibListener extends PacketAdapter {
}
public static void register(FastLoginBukkit plugin, RateLimiter rateLimiter) {
//they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
// they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
// TODO: make synchronous processing, but do web or database requests async
ProtocolLibrary.getProtocolManager()
.getAsynchronousManager()
.registerAsyncHandler(new ProtocolLibListener(plugin, rateLimiter))
@@ -72,16 +75,21 @@ public class ProtocolLibListener extends PacketAdapter {
@Override
public void onPacketReceiving(PacketEvent packetEvent) {
if (packetEvent.isCancelled()
|| plugin.getCore().getAuthPluginHook()== null
|| plugin.getCore().getAuthPluginHook() == null
|| !plugin.isServerFullyStarted()) {
return;
}
if (isFastLoginPacket(packetEvent)) {
// this is our own packet
return;
}
Player sender = packetEvent.getPlayer();
PacketType packetType = packetEvent.getPacketType();
if (packetType == START) {
if (!rateLimiter.tryAcquire()) {
plugin.getLog().warn("Join limit hit - Ignoring player {}", sender);
plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", sender);
return;
}
@@ -91,6 +99,12 @@ public class ProtocolLibListener extends PacketAdapter {
}
}
private Boolean isFastLoginPacket(PacketEvent packetEvent) {
return packetEvent.getPacket().getMeta(SOURCE_META_KEY)
.map(val -> val.equals(plugin.getName()))
.orElse(false);
}
private void onEncryptionBegin(PacketEvent packetEvent, Player sender) {
byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0);
@@ -113,7 +127,7 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username, keyPair.getPublic());
Runnable nameCheckTask = new NameCheckTask(plugin, random, player, packetEvent, username, keyPair.getPublic());
plugin.getScheduler().runAsync(nameCheckTask);
}
}

View File

@@ -28,7 +28,6 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.github.games647.fastlogin.core.shared.LoginSource;
@@ -46,7 +45,6 @@ import static com.comphenix.protocol.PacketType.Login.Server.ENCRYPTION_BEGIN;
class ProtocolLibLoginSource implements LoginSource {
private final PacketEvent packetEvent;
private final Player player;
private final Random random;
@@ -55,15 +53,14 @@ class ProtocolLibLoginSource implements LoginSource {
private final String serverId = "";
private byte[] verifyToken;
public ProtocolLibLoginSource(PacketEvent packetEvent, Player player, Random random, PublicKey publicKey) {
this.packetEvent = packetEvent;
public ProtocolLibLoginSource(Player player, Random random, PublicKey publicKey) {
this.player = player;
this.random = random;
this.publicKey = publicKey;
}
@Override
public void setOnlineMode() throws Exception {
public void enableOnlinemode() throws Exception {
verifyToken = EncryptionUtil.generateVerifyToken(random);
/*
@@ -109,7 +106,7 @@ class ProtocolLibLoginSource implements LoginSource {
@Override
public InetSocketAddress getAddress() {
return packetEvent.getPlayer().getAddress();
return player.getAddress();
}
public String getServerId() {
@@ -123,8 +120,7 @@ class ProtocolLibLoginSource implements LoginSource {
@Override
public String toString() {
return this.getClass().getSimpleName() + '{' +
"packetEvent=" + packetEvent +
", player=" + player +
"player=" + player +
", random=" + random +
", serverId='" + serverId + '\'' +
", verifyToken=" + Arrays.toString(verifyToken) +

View File

@@ -140,7 +140,7 @@ public class VerifyResponseTask implements Runnable {
Optional<Verification> response = resolver.hasJoined(requestedUsername, serverId, address);
if (response.isPresent()) {
Verification verification = response.get();
plugin.getLog().info("Profile {} has a verified premium account: {}", requestedUsername, verification);
plugin.getLog().info("Profile {} has a verified premium account", requestedUsername);
String realUsername = verification.getName();
if (realUsername == null) {
disconnect("invalid-session", true, "Username field null for {}", requestedUsername);
@@ -188,7 +188,7 @@ public class VerifyResponseTask implements Runnable {
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
//check if the verify token are equal to the server sent one
//check if the verify-token are equal to the server sent one
disconnect("invalid-verify-token", true
, "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
, session.getRequestUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
@@ -202,13 +202,14 @@ public class VerifyResponseTask implements Runnable {
private Object getNetworkManager() throws IllegalAccessException, ClassNotFoundException {
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
//ChannelInjector
// ChannelInjector
Class<?> injectorClass = Class.forName("com.comphenix.protocol.injector.netty.Injector");
Object rawInjector = FuzzyReflection.getFieldValue(injectorContainer, injectorClass, true);
return FieldUtils.readField(rawInjector, "networkManager", true);
}
private boolean enableEncryption(SecretKey loginKey) throws IllegalArgumentException {
plugin.getLog().info("Enabling onlinemode encryption for {}", player.getAddress());
// Initialize method reflections
if (encryptMethod == null) {
Class<?> networkManagerClass = MinecraftReflection.getNetworkManagerClass();
@@ -285,7 +286,8 @@ public class VerifyResponseTask implements Runnable {
startPacket.getGameProfiles().write(0, fakeProfile);
try {
//we don't want to handle our own packets so ignore filters
ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, false);
startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, true);
} catch (InvocationTargetException | IllegalAccessException ex) {
plugin.getLog().warn("Failed to fake a new start packet for: {}", username, ex);
//cancel the event in order to prevent the server receiving an invalid packet

View File

@@ -40,7 +40,7 @@ public class ProtocolLoginSource implements LoginSource {
}
@Override
public void setOnlineMode() {
public void enableOnlinemode() {
loginStartEvent.setOnlineMode(true);
}
@@ -51,7 +51,7 @@ public class ProtocolLoginSource implements LoginSource {
@Override
public InetSocketAddress getAddress() {
return loginStartEvent.getAddress();
return loginStartEvent.getConnection().getRawAddress();
}
public PlayerLoginStartEvent getLoginStartEvent() {

View File

@@ -66,12 +66,12 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
}
if (!rateLimiter.tryAcquire()) {
plugin.getLog().warn("Join limit hit - Ignoring player {}", loginStartEvent.getConnection());
plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", loginStartEvent.getConnection());
return;
}
String username = loginStartEvent.getConnection().getProfile().getName();
InetSocketAddress address = loginStartEvent.getAddress();
InetSocketAddress address = loginStartEvent.getConnection().getRawAddress();
//remove old data every time on a new login in order to keep the session only for one person
plugin.removeSession(address);
@@ -82,13 +82,14 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
@EventHandler
public void onConnectionClosed(ConnectionCloseEvent closeEvent) {
InetSocketAddress address = closeEvent.getConnection().getAddress();
InetSocketAddress address = closeEvent.getConnection().getRawAddress();
plugin.removeSession(address);
}
@EventHandler
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
InetSocketAddress address = profileCompleteEvent.getAddress();
InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress();
BukkitLoginSession session = plugin.getSession(address);
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
@@ -112,7 +113,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
@Override
public void requestPremiumLogin(ProtocolLoginSource source, StoredProfile profile, String username
, boolean registered) {
source.setOnlineMode();
source.enableOnlinemode();
String ip = source.getAddress().getAddress().getHostAddress();
plugin.getCore().getPendingLogin().put(ip + username, new Object());

View File

@@ -25,94 +25,27 @@
*/
package com.github.games647.fastlogin.bukkit.task;
import java.io.IOException;
import java.util.Optional;
import java.net.InetSocketAddress;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.FloodgateManagement;
public class FloodgateAuthTask implements Runnable {
public class FloodgateAuthTask extends FloodgateManagement<Player, CommandSender, BukkitLoginSession, FastLoginBukkit> {
private final FastLoginBukkit plugin;
private final Player player;
private final FloodgatePlayer floodgatePlayer;
public FloodgateAuthTask(FastLoginBukkit plugin, Player player, FloodgatePlayer floodgatePlayer) {
this.plugin = plugin;
this.player = player;
this.floodgatePlayer = floodgatePlayer;
public FloodgateAuthTask(FastLoginCore<Player, CommandSender, FastLoginBukkit> core, Player player, FloodgatePlayer floodgatePlayer) {
super(core, player, floodgatePlayer);
}
@Override
public void run() {
plugin.getLog().info(
"Player {} is connecting through Geyser Floodgate.",
player.getName());
// check if the Bedrock player is linked to a Java account
boolean isLinked = floodgatePlayer.getLinkedPlayer() != null;
AuthPlugin<Player> authPlugin = plugin.getCore().getAuthPluginHook();
String autoLoginFloodgate = plugin.getCore().getConfig().get("autoLoginFloodgate").toString().toLowerCase();
String autoRegisterFloodgate = plugin.getCore().getConfig().get("autoRegisterFloodgate").toString().toLowerCase();
String allowNameConflict = plugin.getCore().getConfig().get("allowFloodgateNameConflict").toString().toLowerCase();
boolean isRegistered;
try {
isRegistered = authPlugin.isRegistered(player.getName());
} catch (Exception e) {
plugin.getLog().error(
"An error has occured while checking if player {} is registered",
player.getName());
return;
}
//decide if checks should be made for conflicting Java player names
if (!isLinked //linked players have the same name as their Java profile
// if allowNameConflict is 'false' or 'linked' and the player had a conflicting
// name, than they would have been kicked in FloodgateHook#checkNameConflict
&& allowNameConflict.equals("true") &&
(
autoLoginFloodgate.equals("no-conflict")
|| !isRegistered && autoRegisterFloodgate.equals("no-conflict"))
) {
// check for conflicting Premium Java name
Optional<Profile> premiumUUID = Optional.empty();
try {
premiumUUID = plugin.getCore().getResolver().findProfile(player.getName());
} catch (IOException | RateLimitException e) {
plugin.getLog().error(
"Could not check wether Floodgate Player {}'s name conflits a premium Java player's name.",
player.getName());
return;
}
//stop execution if player's name is conflicting
if (premiumUUID.isPresent()) {
return;
}
}
if (!isRegistered && autoRegisterFloodgate.equals("false")) {
plugin.getLog().info(
"Auto registration is disabled for Floodgate players in config.yml");
return;
}
// logging in from bedrock for a second time threw an error with UUID
StoredProfile profile = plugin.getCore().getStorage().loadProfile(player.getName());
if (profile == null) {
profile = new StoredProfile(player.getUniqueId(), player.getName(), true, player.getAddress().toString());
}
protected void startLogin() {
BukkitLoginSession session = new BukkitLoginSession(player.getName(), isRegistered, profile);
// enable auto login based on the value of 'autoLoginFloodgate' in config.yml
@@ -120,8 +53,20 @@ public class FloodgateAuthTask implements Runnable {
|| (autoLoginFloodgate.equals("linked") && isLinked));
// run login task
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
Runnable forceLoginTask = new ForceLoginTask(core.getPlugin().getCore(), player, session);
Bukkit.getScheduler().runTaskAsynchronously(core.getPlugin(), forceLoginTask);
}
protected String getName(Player player) {
return player.getName();
}
protected UUID getUUID(Player player) {
return player.getUniqueId();
}
protected InetSocketAddress getAddress(Player player) {
return player.getAddress();
}
}

View File

@@ -155,6 +155,12 @@
<artifactId>BungeeCordAuthenticator</artifactId>
<version>0.0.2</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@@ -46,7 +46,7 @@ public class BungeeLoginSource implements LoginSource {
}
@Override
public void setOnlineMode() {
public void enableOnlinemode() {
connection.setOnlineMode(true);
}

View File

@@ -86,14 +86,7 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
//events
PluginManager pluginManager = getProxy().getPluginManager();
//check Floodgate version
String floodgateVersion = "0";
Plugin floodgatePlugin = pluginManager.getPlugin("floodgate");
if (floodgatePlugin != null) {
floodgateVersion = floodgatePlugin.getDescription().getVersion();
}
ConnectListener connectListener = new ConnectListener(this, core.getRateLimiter(), floodgateVersion);
ConnectListener connectListener = new ConnectListener(this, core.getRateLimiter());
pluginManager.registerListener(this, connectListener);
pluginManager.registerListener(this, new PluginMessageListener(this));

View File

@@ -1,9 +0,0 @@
package com.github.games647.fastlogin.bungee.hook.floodgate;
import java.util.UUID;
public interface FloodgateHook {
boolean isBedrockPlayer(UUID uuid);
}

View File

@@ -1,14 +0,0 @@
package com.github.games647.fastlogin.bungee.hook.floodgate;
import org.geysermc.floodgate.FloodgateAPI;
import java.util.UUID;
public class FloodgateV1Hook implements FloodgateHook {
@Override
public boolean isBedrockPlayer(UUID uuid) {
return FloodgateAPI.isBedrockPlayer(uuid);
}
}

View File

@@ -1,21 +0,0 @@
package com.github.games647.fastlogin.bungee.hook.floodgate;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import java.util.UUID;
public class FloodgateV2Hook implements FloodgateHook {
private FloodgateApi floodgateApi;
public FloodgateV2Hook() {
this.floodgateApi = InstanceHolder.getApi();
}
@Override
public boolean isBedrockPlayer(UUID uuid) {
return floodgateApi.isFloodgatePlayer(uuid);
}
}

View File

@@ -28,10 +28,8 @@ package com.github.games647.fastlogin.bungee.listener;
import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.hook.floodgate.FloodgateHook;
import com.github.games647.fastlogin.bungee.hook.floodgate.FloodgateV1Hook;
import com.github.games647.fastlogin.bungee.hook.floodgate.FloodgateV2Hook;
import com.github.games647.fastlogin.bungee.task.AsyncPremiumCheck;
import com.github.games647.fastlogin.bungee.task.FloodgateAuthTask;
import com.github.games647.fastlogin.bungee.task.ForceLoginTask;
import com.github.games647.fastlogin.core.RateLimiter;
import com.github.games647.fastlogin.core.StoredProfile;
@@ -58,6 +56,8 @@ import net.md_5.bungee.connection.LoginResult.Property;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -96,31 +96,21 @@ public class ConnectListener implements Listener {
private final FastLoginBungee plugin;
private final RateLimiter rateLimiter;
private final Property[] emptyProperties = {};
private final FloodgateHook floodgateHook;
public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter, String floodgateVersion) {
public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter) {
this.plugin = plugin;
this.rateLimiter = rateLimiter;
// Get the appropriate floodgate api hook based on the version
if (floodgateVersion.startsWith("1")) {
this.floodgateHook = new FloodgateV1Hook();
} else if (floodgateVersion.startsWith("2")) {
this.floodgateHook = new FloodgateV2Hook();
} else {
this.floodgateHook = null;
}
}
@EventHandler
public void onPreLogin(PreLoginEvent preLoginEvent) {
PendingConnection connection = preLoginEvent.getConnection();
if (preLoginEvent.isCancelled() || isBedrockPlayer(connection.getUniqueId())) {
if (preLoginEvent.isCancelled()) {
return;
}
if (!rateLimiter.tryAcquire()) {
plugin.getLog().warn("Join limit hit - Ignoring player {}", connection);
plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", connection);
return;
}
@@ -194,6 +184,15 @@ public class ConnectListener implements Listener {
ProxiedPlayer player = serverConnectedEvent.getPlayer();
Server server = serverConnectedEvent.getServer();
if (plugin.isPluginInstalled("floodgate")) {
FloodgatePlayer floodgatePlayer = FloodgateApi.getInstance().getPlayer(player.getUniqueId());
if (floodgatePlayer != null) {
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer, server);
plugin.getScheduler().runAsync(floodgateAuthTask);
return;
}
}
BungeeLoginSession session = plugin.getSession().get(player.getPendingConnection());
if (session == null) {
return;
@@ -212,16 +211,4 @@ public class ConnectListener implements Listener {
plugin.getSession().remove(player.getPendingConnection());
plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
}
private boolean isBedrockPlayer(UUID correctedUUID) {
// Floodgate will set a correct UUID at the beginning of the PreLoginEvent
// and will cancel the online mode login for those players
// Therefore we just ignore those
if (floodgateHook == null || correctedUUID == null) {
// Also ignore if not set by floodgate or any other plugin
return false;
}
return this.floodgateHook.isBedrockPlayer(correctedUUID);
}
}

View File

@@ -78,7 +78,7 @@ public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSend
@Override
public void requestPremiumLogin(BungeeLoginSource source, StoredProfile profile,
String username, boolean registered) {
source.setOnlineMode();
source.enableOnlinemode();
plugin.getSession().put(source.getConnection(), new BungeeLoginSession(username, registered, profile));
String ip = source.getAddress().getAddress().getHostAddress();

View File

@@ -0,0 +1,82 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2021 <Your name and contributors>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.games647.fastlogin.bungee.task;
import java.net.InetSocketAddress;
import java.util.UUID;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.FloodgateManagement;
public class FloodgateAuthTask
extends FloodgateManagement<ProxiedPlayer, CommandSender, BungeeLoginSession, FastLoginBungee> {
private final Server server;
public FloodgateAuthTask(FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core, ProxiedPlayer player,
FloodgatePlayer floodgatePlayer, Server server) {
super(core, player, floodgatePlayer);
this.server = server;
}
@Override
protected void startLogin() {
BungeeLoginSession session = new BungeeLoginSession(player.getName(), isRegistered, profile);
// enable auto login based on the value of 'autoLoginFloodgate' in config.yml
boolean forcedOnlineMode = autoLoginFloodgate.equals("true")
|| (autoLoginFloodgate.equals("linked") && isLinked);
// run login task
Runnable forceLoginTask = new ForceLoginTask(core.getPlugin().getCore(), player, server, session,
forcedOnlineMode);
core.getPlugin().getScheduler().runAsync(forceLoginTask);
}
@Override
protected String getName(ProxiedPlayer player) {
return player.getName();
}
@Override
protected UUID getUUID(ProxiedPlayer player) {
return player.getUniqueId();
}
@Override
protected InetSocketAddress getAddress(ProxiedPlayer player) {
return player.getAddress();
}
}

View File

@@ -49,11 +49,21 @@ public class ForceLoginTask
private final Server server;
//treat player as if they had a premium account, even when they don't
//used for Floodgate auto login/register
private final boolean forcedOnlineMode;
public ForceLoginTask(FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core,
ProxiedPlayer player, Server server, BungeeLoginSession session) {
ProxiedPlayer player, Server server, BungeeLoginSession session, boolean forcedOnlineMode) {
super(core, player, session);
this.server = server;
this.forcedOnlineMode = forcedOnlineMode;
}
public ForceLoginTask(FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core, ProxiedPlayer player,
Server server, BungeeLoginSession session) {
this(core, player, server, session, false);
}
@Override
@@ -116,6 +126,6 @@ public class ForceLoginTask
@Override
public boolean isOnlineMode() {
return player.getPendingConnection().isOnlineMode();
return forcedOnlineMode || player.getPendingConnection().isOnlineMode();
}
}

View File

@@ -67,14 +67,14 @@
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.1</version>
<version>4.0.3</version>
</dependency>
<!--Logging framework implements slf4j which is required by hikari-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.30</version>
<version>1.7.32</version>
</dependency>
<!-- snakeyaml is present in Bungee, Spigot, Cauldron and so we could use this independent implementation -->

View File

@@ -25,14 +25,14 @@
*/
package com.github.games647.fastlogin.core.hooks;
import java.io.IOException;
import java.util.Optional;
import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.LoginSource;
import java.io.IOException;
import java.util.Optional;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
@@ -69,17 +69,18 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
"Could not check wether Floodgate Player {}'s name conflicts a premium Java player's name.",
username);
try {
source.kick("Could not check if your name conflicts an existing Java Premium Player's name");
source.kick("Could not check if your name conflicts an existing premium Java account's name.\n"
+ "This is usually a serverside error.");
} catch (Exception e1) {
core.getPlugin().getLog().error("Could not kick Player {}", username);
}
}
if (premiumUUID.isPresent()) {
core.getPlugin().getLog().info("Bedrock Player {}'s name conflicts an existing Java Premium Player's name",
core.getPlugin().getLog().info("Bedrock Player {}'s name conflicts an existing premium Java account's name",
username);
try {
source.kick("Your name conflicts an existing Java Premium Player's name");
source.kick("Your name conflicts an existing premium Java account's name");
} catch (Exception e) {
core.getPlugin().getLog().error("Could not kick Player {}", username);
}
@@ -105,7 +106,7 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
}
}
}
return null;
}
}

View File

@@ -0,0 +1,158 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2021 <Your name and contributors>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.games647.fastlogin.core.shared;
import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Optional;
import java.util.UUID;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
public abstract class FloodgateManagement<P extends C, C, L extends LoginSession, T extends PlatformPlugin<C>>
implements Runnable {
protected final FastLoginCore<P, C, T> core;
protected final P player;
private final FloodgatePlayer floodgatePlayer;
private final String username;
//config.yml values that might be accessed by multiple methods
protected final String autoLoginFloodgate;
protected final String autoRegisterFloodgate;
protected final String allowNameConflict;
//variables initialized through run() and accesses by subclasss
protected boolean isRegistered;
protected StoredProfile profile;
protected boolean isLinked;
public FloodgateManagement(FastLoginCore<P, C, T> core, P player, FloodgatePlayer floodgatePlayer) {
this.core = core;
this.player = player;
this.floodgatePlayer = floodgatePlayer;
this.username = getName(player);
//load values from config.yml
autoLoginFloodgate = core.getConfig().get("autoLoginFloodgate").toString().toLowerCase();
autoRegisterFloodgate = core.getConfig().get("autoRegisterFloodgate").toString().toLowerCase();
allowNameConflict = core.getConfig().get("allowFloodgateNameConflict").toString().toLowerCase();
}
@Override
public void run() {
core.getPlugin().getLog().info("Player {} is connecting through Geyser Floodgate.", username);
// check if the Bedrock player is linked to a Java account
isLinked = floodgatePlayer.getLinkedPlayer() != null;
AuthPlugin<P> authPlugin = core.getAuthPluginHook();
try {
isRegistered = authPlugin.isRegistered(username);
} catch (Exception ex) {
core.getPlugin().getLog().error(
"An error has occured while checking if player {} is registered",
username, ex);
return;
}
//decide if checks should be made for conflicting Java player names
if (isNameCheckRequired()) {
// check for conflicting Premium Java name
Optional<Profile> premiumUUID = Optional.empty();
try {
premiumUUID = core.getResolver().findProfile(username);
} catch (IOException | RateLimitException e) {
core.getPlugin().getLog().error(
"Could not check whether Floodgate Player {}'s name conflicts a premium Java account's name.",
username, e);
return;
}
//stop execution if player's name is conflicting
if (premiumUUID.isPresent()) {
return;
}
}
if (!isRegistered && !isAutoRegisterAllowed()) {
return;
}
//logging in from bedrock for a second time threw an error with UUID
profile = core.getStorage().loadProfile(username);
if (profile == null) {
profile = new StoredProfile(getUUID(player), username, true, getAddress(player).toString());
}
//start Bukkit/Bungee specific tasks
startLogin();
}
/**
* Decude if the player can be auto registered.
* The config option 'non-conflicting' is ignored by this function.
* @return true if the Player can be registered automatically
*/
private boolean isAutoRegisterAllowed() {
return "true".equals(autoRegisterFloodgate)
|| "no-conflict".equals(autoRegisterFloodgate) // this was checked before
|| ("linked".equals(autoRegisterFloodgate) && isLinked);
}
/**
* Decides wether checks for conflicting Java names should be made
* @return ture if an API call to Mojang is needed
*/
private boolean isNameCheckRequired() {
//linked players have the same name as their Java profile
//OR
//if allowNameConflict is 'false' or 'linked' and the player had a conflicting
//name, than they would have been kicked in FloodgateHook#checkNameConflict
if (isLinked || !"true".equals(allowNameConflict)) {
return false;
}
//autoRegisterFloodgate should only be checked if then player is not yet registered
if (!isRegistered && "no-conflict".equals(autoRegisterFloodgate)) {
return true;
}
return "no-conflict".equals(autoLoginFloodgate);
}
protected abstract void startLogin();
protected abstract String getName(P player);
protected abstract UUID getUUID(P player);
protected abstract InetSocketAddress getAddress(P player);
}

View File

@@ -29,7 +29,7 @@ import java.net.InetSocketAddress;
public interface LoginSource {
void setOnlineMode() throws Exception;
void enableOnlinemode() throws Exception;
void kick(String message) throws Exception;

View File

@@ -16,9 +16,9 @@ anti-bot:
# Image the following like bucket. The following is total amount that is allowed in this bucket, while expire
# means how long it takes for every entry to expire.
# Total number of connections
connections: 200
# Amount of minutes after the first connection will expire and made available
expire: 5
connections: 600
# Amount of minutes after the first connection got inserted will expire and made available
expire: 10
# Request a premium login without forcing the player to type a command
#
@@ -189,8 +189,6 @@ autoLogin: true
# Floodgate configuration
# Connecing through Floodgate requires player's to sign in via their Xbox Live account
# Requires Floodgate 2.0 https://github.com/GeyserMC/Floodgate/tree/dev/2.0
# These settings only work in Bukkit/Spigot/Paper mode
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
# Enabling any of these settings might lead to people gaining unauthorized access to other's accounts!
@@ -202,6 +200,7 @@ autoLogin: true
# no-conflict: Bedrock players will only be automatically logged in if the Mojang API reports
# that there is no existing Premium Java MC account with their name.
# This option can be useful if you are not using 'username-prefix' in floodgate/config.yml
# Requires 'autoLogin' to be 'true'
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
# Enabling this might lead to people gaining unauthorized access to other's accounts!
autoLoginFloodgate: false
@@ -221,7 +220,6 @@ autoLoginFloodgate: false
#
# Possible values:
# false: Check for Premium Java name conflicts as described in 'autoRegister'
# 'autoRegister' must be 'true' for this to work
# Note: Linked players have the same name as their Java profile, so the Bedrock player will always conflict
# their own Java account's name. Therefore, setting this to false will prevent any linked player from joining.
# true: Bypass 'autoRegister's name conflict checking
@@ -235,9 +233,11 @@ allowFloodgateNameConflict: false
# Possible values:
# false: Disables auto registering for every player connecting through Floodgate
# true: Enables auto registering for every player connecting through Floodgate
# linked: Only Bedrock accounts that are linked to a Java account will be registered automatically
# no-conflict: Bedrock players will only be automatically registered if the Mojang API reports
# that there is no existing Premium Java MC account with their name.
# This option can be useful if you are not using 'username-prefix' in floodgate/config.yml
# Requires 'autoRegister' to be 'true'
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
# Enabling this might lead to people gaining unauthorized access to other's accounts!
autoRegisterFloodgate: false