mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-12-24 15:48:07 +01:00
Compare commits
2 Commits
floodgate-
...
test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44abe78213 | ||
|
|
6f69f73bad |
8
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
8
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -36,7 +36,7 @@ body:
|
||||
attributes:
|
||||
label: Server log
|
||||
description: The error, stacktrace or link the complete log. You can use the links above for long versions.
|
||||
placeholder: https://www.toptal.com/developers/hastebin / https://gist.github.com/
|
||||
placeholder: https://hastebin.com/ / https://gist.github.com/
|
||||
- type: input
|
||||
attributes:
|
||||
label: Plugin version
|
||||
@@ -59,11 +59,9 @@ body:
|
||||
label: Relevance
|
||||
description: Check list for previous tickets
|
||||
options:
|
||||
- label: |
|
||||
I tried the [latest build](https://ci.codemc.io/job/Games647/job/FastLogin/)
|
||||
(build refers to development builds not necessary a release version; i.e. v1.10 is out of date)
|
||||
- label: I tried the latest build (build refers to development builds not necessary a release version)
|
||||
required: true
|
||||
- label: |
|
||||
I checked for existing tickets -
|
||||
If there are, please vote them with a thumbs reaction and not create new ones
|
||||
If there are, please vote them with a thumps reaction and not create new ones
|
||||
required: true
|
||||
|
||||
30
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: 💡 Enhancement request
|
||||
about: New feature or change request
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
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 [...])
|
||||
|
||||
### Describe the solution you'd like
|
||||
|
||||
[//]: # (A clear and concise description of what you want to happen.)
|
||||
|
||||
### Describe alternatives you've considered
|
||||
|
||||
[//]: # (A clear and concise description of any alternative solutions or features you've considered.)
|
||||
|
||||
### Additional context
|
||||
|
||||
[//]: # (Add any other context or screenshots about the feature request here.)
|
||||
43
.github/ISSUE_TEMPLATE/enhancement_request.yaml
vendored
43
.github/ISSUE_TEMPLATE/enhancement_request.yaml
vendored
@@ -1,43 +0,0 @@
|
||||
name: 💡 Enhancement request
|
||||
description: New feature or change request
|
||||
labels: [ enhancement ]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This ticket is about suggestions for a feature or particular enhancement.
|
||||
Feedback about this form is appreciated.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Platform
|
||||
description: Server software - choose your proxy software if you have multiple servers
|
||||
options:
|
||||
- Spigot
|
||||
- BungeeCord
|
||||
- Velocity
|
||||
- All / Shared
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Relevance
|
||||
description: Check list for previous tickets
|
||||
options:
|
||||
- label: |
|
||||
I checked for existing tickets -
|
||||
If there are, please vote them with a thumbs reaction and not create new ones
|
||||
required: true
|
||||
19
.github/dependabot.yml
vendored
19
.github/dependabot.yml
vendored
@@ -14,22 +14,3 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: "production"
|
||||
development-dependencies:
|
||||
dependency-type: "development"
|
||||
exclude-patterns:
|
||||
# Create single PR for these
|
||||
# Plugin require special evaluation about their compatibility
|
||||
- "com.lenis0012.bukkit:loginsecurity"
|
||||
- "com.comphenix.protocol:ProtocolLib"
|
||||
|
||||
ignore:
|
||||
# HikariCP dropped Java 8 support with 5.0
|
||||
- dependency-name: "com.zaxxer:HikariCP"
|
||||
update-types: ["version-update:semver-major"]
|
||||
# SnakeYAML has breaking changes with 2.0
|
||||
- dependency-name: "org.yaml:snakeyaml"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
43
.github/workflows/codeql-analysis.yml
vendored
43
.github/workflows/codeql-analysis.yml
vendored
@@ -4,11 +4,11 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Maven Build"]
|
||||
branches: [main]
|
||||
types:
|
||||
- completed
|
||||
# Scan only for push on the primary branch for now
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
# job i
|
||||
@@ -20,10 +20,6 @@ jobs:
|
||||
# Environment
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -37,29 +33,28 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version-file: '.java-version'
|
||||
java-version: 19
|
||||
cache: 'maven'
|
||||
|
||||
# Manually start the autobuild process, because autobuild always selects Java 8 as build toolchain, but
|
||||
# we are doing cross-crompiling from a newer Java version
|
||||
- name: Build with Maven
|
||||
# Extracted from autobuild
|
||||
run: mvn package -f "pom.xml" --batch-mode -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip -DskipTests -Dmaven.test.skip.exec -Dlicense.skip=true -Drat.skip=true -Dspotless.check.skip=true -t /home/runner/.m2/toolchains.xml
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Auto build attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
12
.github/workflows/maven.yml
vendored
12
.github/workflows/maven.yml
vendored
@@ -21,19 +21,19 @@ jobs:
|
||||
# Environment image - always use the newest OS
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
# Run steps
|
||||
steps:
|
||||
# Pull changes
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Setup Java
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version-file: '.java-version'
|
||||
java-version: 19
|
||||
cache: 'maven'
|
||||
|
||||
# Build and test (included in package)
|
||||
@@ -41,7 +41,3 @@ jobs:
|
||||
# Run non-interactive, package (with compile+test),
|
||||
# ignore snapshot updates, because they are likely to have breaking changes, enforce checksums
|
||||
run: mvn test --batch-mode --threads 2.0C --no-snapshot-updates --strict-checksums --file pom.xml
|
||||
|
||||
- name: Update dependency graph
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: advanced-security/maven-dependency-submission-action@v4.0.0
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# Latest GitHub Action java release that is installed on the runners
|
||||
21
|
||||
@@ -50,7 +50,7 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
@@ -207,7 +207,7 @@
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.0.0</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@@ -278,7 +278,7 @@
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.5</version>
|
||||
<version>2.11.3</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
@@ -307,7 +307,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lenis0012.bukkit</groupId>
|
||||
<artifactId>loginsecurity</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.1.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
@@ -378,7 +378,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
<version>1.77</version>
|
||||
<version>1.72</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -228,22 +228,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
|
||||
/**
|
||||
* Fetches the premium status of an online player.
|
||||
* {@snippet :
|
||||
* // Bukkit's players object after successful authentication i.e. PlayerJoinEvent
|
||||
* // except for proxies like BungeeCord and Velocity where the details are sent delayed (1-2 seconds)
|
||||
* Player player;
|
||||
* PremiumStatus status = JavaPlugin.getPlugin(FastLoginBukkit.class).getStatus(player.getUniqueId());
|
||||
* switch (status) {
|
||||
* case CRACKED:
|
||||
* // player is offline
|
||||
* break;
|
||||
* case PREMIUM:
|
||||
* // account is premium and player passed the verification
|
||||
* break;
|
||||
* case UNKNOWN:
|
||||
* // no record about this player
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param onlinePlayer player that is currently online player (play state)
|
||||
* @return the online status or unknown if an error happened, the player isn't online or BungeeCord doesn't send
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 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.bukkit;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public final class InetUtils {
|
||||
|
||||
private InetUtils() {
|
||||
// Utility
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the given IP address is from the local network
|
||||
*
|
||||
* @param address IP address
|
||||
* @return true if address is from local network or even from the device itself (loopback)
|
||||
*/
|
||||
public static boolean isLocalAddress(InetAddress address) {
|
||||
// Loopback addresses like 127.0.* (IPv4) or [::1] (IPv6)
|
||||
return address.isLoopbackAddress()
|
||||
// Example: 10.0.0.0, 172.16.0.0, 192.168.0.0, fec0::/10 (deprecated)
|
||||
// Ref: https://en.wikipedia.org/wiki/IP_address#Private_addresses
|
||||
|| address.isSiteLocalAddress()
|
||||
// Example: 169.254.0.0/16, fe80::/10
|
||||
// Ref: https://en.wikipedia.org/wiki/IP_address#Address_autoconfiguration
|
||||
|| address.isLinkLocalAddress()
|
||||
// non deprecated unique site-local that java doesn't check yet -> fc00::/7
|
||||
|| isIPv6UniqueSiteLocal(address);
|
||||
}
|
||||
|
||||
private static boolean isIPv6UniqueSiteLocal(InetAddress address) {
|
||||
// ref: https://en.wikipedia.org/wiki/Unique_local_address
|
||||
|
||||
// currently undefined but could be used in the near future fc00::/8
|
||||
return (address.getAddress()[0] & 0xFF) == 0xFC
|
||||
// in use for unique site-local fd00::/8
|
||||
|| (address.getAddress()[0] & 0xFF) == 0xFD;
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ final class EncryptionUtil {
|
||||
public static final int VERIFY_TOKEN_LENGTH = 4;
|
||||
public static final String KEY_PAIR_ALGORITHM = "RSA";
|
||||
|
||||
private static final int RSA_LENGTH = 2_048;
|
||||
private static final int RSA_LENGTH = 1_024;
|
||||
|
||||
private static final PublicKey MOJANG_SESSION_KEY;
|
||||
private static final int LINE_LENGTH = 76;
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
|
||||
@@ -47,7 +46,6 @@ import com.github.games647.craftapi.model.skin.SkinProperty;
|
||||
import com.github.games647.craftapi.resolver.MojangResolver;
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.InetUtils;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import lombok.val;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -73,17 +71,10 @@ public class VerifyResponseTask implements Runnable {
|
||||
|
||||
private static final String ENCRYPTION_CLASS_NAME = "MinecraftEncryption";
|
||||
private static final Class<?> ENCRYPTION_CLASS;
|
||||
private static final String ADDRESS_VERIFY_WARNING = "This indicates the use of reverse-proxy like HAProxy, "
|
||||
+ "TCPShield, BungeeCord, Velocity, etc. "
|
||||
+ "By default (configurable in the config) this plugin requests Mojang to verify the connecting IP "
|
||||
+ "to this server with the one used to log into Minecraft to prevent MITM attacks. In "
|
||||
+ "order to work this security feature, the actual client IP needs to be forwarding "
|
||||
+ "(keyword IP forwarding). This process will also be useful for other server "
|
||||
+ "features like IP banning, so that it doesn't ban the proxy IP.";
|
||||
|
||||
static {
|
||||
ENCRYPTION_CLASS = MinecraftReflection.getMinecraftClass(
|
||||
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
|
||||
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
|
||||
);
|
||||
}
|
||||
|
||||
@@ -158,27 +149,10 @@ public class VerifyResponseTask implements Runnable {
|
||||
} else {
|
||||
//user tried to fake an authentication
|
||||
disconnect(
|
||||
"invalid-session",
|
||||
"Session server rejected incoming connection for GameProfile {} ({}). Possible reasons are"
|
||||
+ "1) Client IP address contacting Mojang and server during server join were different "
|
||||
+ "(Do you use a reverse proxy? -> Enable IP forwarding, "
|
||||
+ "or disable the feature in the config). "
|
||||
+ "2) Player is offline, but tried to bypass the authentication"
|
||||
+ "3) Client uses an outdated username for connecting (Fix: Restart client)",
|
||||
requestedUsername, address
|
||||
"invalid-session",
|
||||
"GameProfile {} ({}) tried to log in with an invalid session. ServerId: {}",
|
||||
session.getRequestUsername(), socketAddress, serverId
|
||||
);
|
||||
|
||||
if (InetUtils.isLocalAddress(address)) {
|
||||
plugin.getLog().warn(
|
||||
"The incoming request for player {} uses a local IP address",
|
||||
requestedUsername
|
||||
);
|
||||
plugin.getLog().warn(ADDRESS_VERIFY_WARNING);
|
||||
} else {
|
||||
plugin.getLog().warn("If you think this is an error, please verify that the incoming "
|
||||
+ "IP address {} is not associated with a server hosting company.", address);
|
||||
plugin.getLog().warn(ADDRESS_VERIFY_WARNING);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioEx) {
|
||||
disconnect("error-kick", "Failed to connect to session server", ioEx);
|
||||
@@ -203,7 +177,7 @@ public class VerifyResponseTask implements Runnable {
|
||||
session.setVerified(true);
|
||||
|
||||
setPremiumUUID(session.getUuid());
|
||||
receiveFakeStartPacket(realUsername, session.getClientPublicKey(), session.getUuid());
|
||||
receiveFakeStartPacket(realUsername, session.getClientPublicKey());
|
||||
}
|
||||
|
||||
private void setPremiumUUID(UUID premiumUUID) {
|
||||
@@ -243,15 +217,15 @@ public class VerifyResponseTask implements Runnable {
|
||||
try {
|
||||
// Try to get the old (pre MC 1.16.4) encryption method
|
||||
encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
|
||||
.getMethodByParameters("a", SecretKey.class);
|
||||
.getMethodByParameters("a", SecretKey.class);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
// Get the new encryption method
|
||||
encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
|
||||
.getMethodByParameters("a", Cipher.class, Cipher.class);
|
||||
.getMethodByParameters("a", Cipher.class, Cipher.class);
|
||||
|
||||
// Get the needed Cipher helper method (used to generate ciphers from login key)
|
||||
cipherMethod = FuzzyReflection.fromClass(ENCRYPTION_CLASS)
|
||||
.getMethodByParameters("a", int.class, Key.class);
|
||||
.getMethodByParameters("a", int.class, Key.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,23 +268,15 @@ public class VerifyResponseTask implements Runnable {
|
||||
}
|
||||
|
||||
//fake a new login packet in order to let the server handle all the other stuff
|
||||
private void receiveFakeStartPacket(String username, ClientPublicKey clientKey, UUID uuid) {
|
||||
private void receiveFakeStartPacket(String username, ClientPublicKey clientKey) {
|
||||
PacketContainer startPacket;
|
||||
if (new MinecraftVersion(1, 20, 2).atOrAbove()) {
|
||||
startPacket = new PacketContainer(START);
|
||||
startPacket.getStrings().write(0, username);
|
||||
startPacket.getUUIDs().write(0, uuid);
|
||||
} else if (new MinecraftVersion(1, 19, 3).atOrAbove()) {
|
||||
startPacket = new PacketContainer(START);
|
||||
startPacket.getStrings().write(0, username);
|
||||
startPacket.getOptionals(Converters.passthrough(UUID.class)).write(0, Optional.of(uuid));
|
||||
} else if (new MinecraftVersion(1, 19, 0).atOrAbove()) {
|
||||
if (new MinecraftVersion(1, 19, 0).atOrAbove()) {
|
||||
startPacket = new PacketContainer(START);
|
||||
startPacket.getStrings().write(0, username);
|
||||
|
||||
EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
|
||||
val wrappedKey = Optional.ofNullable(clientKey).map(key ->
|
||||
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
|
||||
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
|
||||
);
|
||||
|
||||
startPacket.getOptionals(converter).write(0, wrappedKey);
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
|
||||
|
||||
@@ -71,43 +71,25 @@ public class ConnectListener implements Listener {
|
||||
private static final String UUID_FIELD_NAME = "uniqueId";
|
||||
protected static final MethodHandle UNIQUE_ID_SETTER;
|
||||
|
||||
private static final String REWRITE_ID_NAME = "rewriteId";
|
||||
protected static final MethodHandle REWRITE_ID_SETTER;
|
||||
|
||||
static {
|
||||
MethodHandle uniqueIdHandle = null;
|
||||
MethodHandle rewriterHandle = null;
|
||||
MethodHandle setHandle = null;
|
||||
try {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
// test for implementation class availability
|
||||
Class.forName("net.md_5.bungee.connection.InitialHandler");
|
||||
uniqueIdHandle = getHandlerSetter(lookup, UUID_FIELD_NAME);
|
||||
try {
|
||||
rewriterHandle = getHandlerSetter(lookup, REWRITE_ID_NAME);
|
||||
} catch (NoSuchFieldException noSuchFieldEx) {
|
||||
Logger logger = LoggerFactory.getLogger(ConnectListener.class);
|
||||
logger.error(
|
||||
"Rewrite field not found. Setting only legacy BungeeCord field"
|
||||
);
|
||||
}
|
||||
|
||||
Field uuidField = InitialHandler.class.getDeclaredField(UUID_FIELD_NAME);
|
||||
uuidField.setAccessible(true);
|
||||
setHandle = lookup.unreflectSetter(uuidField);
|
||||
} catch (ReflectiveOperationException reflectiveOperationException) {
|
||||
Logger logger = LoggerFactory.getLogger(ConnectListener.class);
|
||||
logger.error(
|
||||
"Cannot find Bungee UUID field implementation; Disabling premium UUID and skin won't work.",
|
||||
"Cannot find Bungee initial handler; Disabling premium UUID and skin won't work.",
|
||||
reflectiveOperationException
|
||||
);
|
||||
}
|
||||
|
||||
UNIQUE_ID_SETTER = uniqueIdHandle;
|
||||
REWRITE_ID_SETTER = rewriterHandle;
|
||||
}
|
||||
|
||||
private static MethodHandle getHandlerSetter(Lookup lookup, String fieldName)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
Field uuidField = InitialHandler.class.getDeclaredField(fieldName);
|
||||
uuidField.setAccessible(true);
|
||||
return lookup.unreflectSetter(uuidField);
|
||||
UNIQUE_ID_SETTER = setHandle;
|
||||
}
|
||||
|
||||
private final FastLoginBungee plugin;
|
||||
@@ -197,12 +179,6 @@ public class ConnectListener implements Listener {
|
||||
// So we have to do it with reflection
|
||||
UNIQUE_ID_SETTER.invokeExact(connection, offlineUUID);
|
||||
|
||||
// if available set rewrite id to forward the UUID for newer BungeeCord versions since
|
||||
// https://github.com/SpigotMC/BungeeCord/commit/1be25b6c74ec2be4b15adf8ca53a0497f01e2afe
|
||||
if (REWRITE_ID_SETTER != null) {
|
||||
REWRITE_ID_SETTER.invokeExact(connection, offlineUUID);
|
||||
}
|
||||
|
||||
String format = "Overridden UUID from {} to {} (based of {}) on {}";
|
||||
plugin.getLog().info(format, oldPremiumId, offlineUUID, username, connection);
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -220,14 +220,6 @@
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Suppress filters via comments -->
|
||||
<!-- https://stackoverflow.com/a/4023351/9767089 -->
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
|
||||
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
|
||||
<property name="checkFormat" value="$1"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
||||
21
core/pom.xml
21
core/pom.xml
@@ -63,23 +63,6 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Automatic-Module-Name>com.github.games647.fastlogin.core</Automatic-Module-Name>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Libraries that we shade into the project -->
|
||||
|
||||
@@ -102,7 +85,7 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>2.0.11</version>
|
||||
<version>2.0.7</version>
|
||||
</dependency>
|
||||
|
||||
<!-- snakeyaml is present in Bungee, Spigot, Cauldron, so we could use this independent implementation -->
|
||||
@@ -195,7 +178,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -25,17 +25,8 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.core.hooks;
|
||||
|
||||
/**
|
||||
* Password generator for your auth plugin.
|
||||
* @param <P> platform dependent player class
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PasswordGenerator<P> {
|
||||
|
||||
/**
|
||||
* Generate a password for a non-registered player
|
||||
* @param player
|
||||
* @return daw
|
||||
*/
|
||||
String getRandomPassword(P player);
|
||||
}
|
||||
|
||||
@@ -80,40 +80,6 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
|
||||
}
|
||||
|
||||
profile = core.getStorage().loadProfile(username);
|
||||
|
||||
if (profile.isSaved()) {
|
||||
if (profile.isFloodgateMigrated()) {
|
||||
if (profile.getFloodgate() == FloodgateState.TRUE && isLinked) {
|
||||
core.getPlugin().getLog()
|
||||
.info("Player {} is already stored by FastLogin as a non-linked Bedrock Edition player",
|
||||
username);
|
||||
return;
|
||||
} else if (profile.getFloodgate() == FloodgateState.FALSE && isLinked) {
|
||||
profile.setFloodgate(FloodgateState.LINKED);
|
||||
core.getPlugin().getLog().info(
|
||||
"Player {} will be changed from a Java player to a linked Floodgate player",
|
||||
username);
|
||||
}
|
||||
} else {
|
||||
if (isLinked) {
|
||||
profile.setFloodgate(FloodgateState.LINKED);
|
||||
core.getPlugin().getLog().info(
|
||||
"Player {} will be migrated to the v2 database schema as a linked Floodgate user",
|
||||
username);
|
||||
} else {
|
||||
profile.setFloodgate(FloodgateState.TRUE);
|
||||
core.getPlugin().getLog().info(
|
||||
"Player {} will be migrated to the v2 database schema as a Floodgate user", username);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isLinked) {
|
||||
profile.setFloodgate(FloodgateState.LINKED);
|
||||
} else {
|
||||
profile.setFloodgate(FloodgateState.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
AuthPlugin<P> authPlugin = core.getAuthPluginHook();
|
||||
|
||||
try {
|
||||
@@ -153,17 +119,13 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
|
||||
}
|
||||
}
|
||||
|
||||
// defer auto registration, if it's not enabled in the config
|
||||
if (!isRegistered && !isAutoAuthAllowed(autoRegisterFloodgate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// stop the auto login procedure, if the current connection's parameters don't match the one stored in our
|
||||
// database
|
||||
// ex. we stored a LINKED account, but the current connection is not linked
|
||||
if ((profile.getFloodgate() == FloodgateState.LINKED && !isLinked)
|
||||
|| (profile.getFloodgate() == FloodgateState.TRUE && isLinked)) {
|
||||
return;
|
||||
//logging in from bedrock for a second time threw an error with UUID
|
||||
if (profile == null) {
|
||||
profile = new StoredProfile(getUUID(player), username, true, getAddress(player).toString());
|
||||
}
|
||||
|
||||
//start Bukkit/Bungee specific tasks
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 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;
|
||||
|
||||
public enum FloodgateState {
|
||||
|
||||
/**
|
||||
* Purely Java profile
|
||||
*/
|
||||
FALSE(0),
|
||||
|
||||
/**
|
||||
* Purely Bedrock profile
|
||||
*/
|
||||
TRUE(1),
|
||||
|
||||
/**
|
||||
* Bedrock profile is bidirectional associated with the Java Mojang profile.
|
||||
*/
|
||||
LINKED(2),
|
||||
|
||||
/**
|
||||
* Data before floodgate database migration. Floodgate state is unknown.
|
||||
*/
|
||||
NOT_MIGRATED(3);
|
||||
|
||||
private int value;
|
||||
|
||||
FloodgateState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a number to FloodgateState
|
||||
* <ol start="0">
|
||||
* <li>False</li>
|
||||
* <li>True</li>
|
||||
* <li>Linked</li>
|
||||
* <li>Not Migrated</li>
|
||||
* </ol>
|
||||
* @param num the number, most likely loaded from the database
|
||||
* @return FloodgateStatus on success, null otherwise
|
||||
*/
|
||||
public static FloodgateState fromInt(int num) {
|
||||
// using Enum.values()[i] is expensive as per https://stackoverflow.com/a/8762387/9767089
|
||||
switch (num) {
|
||||
case 0:
|
||||
return FloodgateState.FALSE;
|
||||
case 1:
|
||||
return FloodgateState.TRUE;
|
||||
case 2:
|
||||
return FloodgateState.LINKED;
|
||||
case 3:
|
||||
return FloodgateState.NOT_MIGRATED;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
|
||||
//premium player
|
||||
AuthPlugin<P> authPlugin = core.getAuthPluginHook();
|
||||
if (authPlugin == null) {
|
||||
// maybe only bungeecord plugin
|
||||
//maybe only bungeecord plugin
|
||||
onForceActionSuccess(session);
|
||||
} else {
|
||||
boolean success = true;
|
||||
|
||||
@@ -49,32 +49,17 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
|
||||
public void onLogin(String username, S source) {
|
||||
core.getPlugin().getLog().info("Handling player {}", username);
|
||||
|
||||
//check if the player is connecting through Bedrock Edition
|
||||
if (bedrockService != null && bedrockService.isBedrockConnection(username)) {
|
||||
//perform Bedrock specific checks and skip Java checks if no longer needed
|
||||
if (bedrockService.performChecks(username, source)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StoredProfile profile = core.getStorage().loadProfile(username);
|
||||
|
||||
//can't be a premium Java player, if it's not saved in the database
|
||||
if (profile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile.isFloodgateMigrated()) {
|
||||
if (profile.getFloodgate() == FloodgateState.TRUE) {
|
||||
// migrated and enabled floodgate player, however the above bedrocks fails, so the current connection
|
||||
// isn't premium
|
||||
//check if the player is connecting through Bedrock Edition
|
||||
if (bedrockService != null && bedrockService.isBedrockConnection(username)) {
|
||||
//perform Bedrock specific checks and skip Java checks, if they are not needed
|
||||
if (bedrockService.performChecks(username, source)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
profile.setFloodgate(FloodgateState.FALSE);
|
||||
core.getPlugin().getLog().info(
|
||||
"Player {} will be migrated to the v2 database schema as a JAVA user", username);
|
||||
}
|
||||
|
||||
callFastLoginPreLoginEvent(username, source, profile);
|
||||
@@ -154,12 +139,6 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
if (core.getConfig().get("nameChangeCheck", false)) {
|
||||
StoredProfile storedProfile = core.getStorage().loadProfile(profile.getId());
|
||||
if (storedProfile != null) {
|
||||
if (storedProfile.getFloodgate() == FloodgateState.TRUE) {
|
||||
core.getPlugin().getLog()
|
||||
.info("Player {} is already stored by FastLogin as a Bedrock Edition player.", username);
|
||||
return false;
|
||||
}
|
||||
|
||||
//uuid exists in the database
|
||||
core.getPlugin().getLog().info("GameProfile {} changed it's username", profile);
|
||||
|
||||
|
||||
@@ -29,20 +29,9 @@ import com.github.games647.fastlogin.core.shared.LoginSession;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
|
||||
/**
|
||||
* This event fires if the plugin performs an auto login on the platform where the login plugin is
|
||||
*
|
||||
* {@snippet :
|
||||
* @EventHandler()
|
||||
* public void onPlayerLogin(FastLoginAutoLoginEvent loginEvent) {
|
||||
* StoredProfile profile = loginEvent.getProfile();
|
||||
* LoginSession session = loginEvent.getSession();
|
||||
*
|
||||
* System.out.println("Player: " + session.getUsername() + " is about to be force logged in");
|
||||
* }
|
||||
* }
|
||||
* This event fires if the plugin performs an auto login on the platform where the login plugin is.
|
||||
*/
|
||||
public interface FastLoginAutoLoginEvent extends FastLoginCancellableEvent {
|
||||
LoginSession getSession();
|
||||
|
||||
StoredProfile getProfile();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,5 @@ package com.github.games647.fastlogin.core.shared.event;
|
||||
public interface FastLoginCancellableEvent {
|
||||
|
||||
boolean isCancelled();
|
||||
|
||||
void setCancelled(boolean cancelled);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
public interface FastLoginPreLoginEvent {
|
||||
|
||||
String getUsername();
|
||||
|
||||
LoginSource getSource();
|
||||
|
||||
StoredProfile getProfile();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
public interface FastLoginPremiumToggleEvent {
|
||||
|
||||
StoredProfile getProfile();
|
||||
|
||||
PremiumToggleReason getReason();
|
||||
|
||||
enum PremiumToggleReason {
|
||||
|
||||
@@ -28,8 +28,6 @@ package com.github.games647.fastlogin.core.storage;
|
||||
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class MySQLStorage extends SQLStorage {
|
||||
|
||||
private static final String JDBC_PROTOCOL = "jdbc:";
|
||||
@@ -70,12 +68,12 @@ public class MySQLStorage extends SQLStorage {
|
||||
}
|
||||
|
||||
private static String buildJDBCUrl(String driver, String host, int port, String database) {
|
||||
MySQLVariant variant = MySQLVariant.fromDriver(driver);
|
||||
if (variant == null) {
|
||||
throw new IllegalArgumentException("Unknown storage driver");
|
||||
String protocol = "mysql";
|
||||
if (driver.contains("mariadb")) {
|
||||
protocol = "mariadb";
|
||||
}
|
||||
|
||||
return variant.getJdbcPrefix() + "://" + host + ':' + port + '/' + database;
|
||||
return protocol + "://" + host + ':' + port + '/' + database;
|
||||
}
|
||||
|
||||
private static void addPerformanceProperties(HikariConfig config) {
|
||||
@@ -108,32 +106,4 @@ public class MySQLStorage extends SQLStorage {
|
||||
// In our case it can be useful to see the time in error messages
|
||||
// config.addDataSourceProperty("maintainTimeStats", false);
|
||||
}
|
||||
|
||||
enum MySQLVariant {
|
||||
|
||||
MYSQL("mysql"),
|
||||
|
||||
MARIADB("mariadb");
|
||||
|
||||
private final String jdbcPrefix;
|
||||
|
||||
public static MySQLVariant fromDriver(String driver) {
|
||||
String normalizedDriver = driver.toLowerCase(Locale.ENGLISH);
|
||||
if (normalizedDriver.contains("mysql")) {
|
||||
return MYSQL;
|
||||
} else if (normalizedDriver.contains("mariadb")) {
|
||||
return MARIADB;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
MySQLVariant(String jdbcPrefix) {
|
||||
this.jdbcPrefix = jdbcPrefix;
|
||||
}
|
||||
|
||||
public String getJdbcPrefix() {
|
||||
return jdbcPrefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,11 @@
|
||||
package com.github.games647.fastlogin.core.storage;
|
||||
|
||||
import com.github.games647.craftapi.UUIDAdapter;
|
||||
import com.github.games647.fastlogin.core.shared.FloodgateState;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -58,19 +56,13 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
+ "UNIQUE (`Name`) "
|
||||
+ ')';
|
||||
|
||||
protected static final String ADD_FLOODGATE_COLUMN_STMT = "ALTER TABLE `" + PREMIUM_TABLE
|
||||
+ "` ADD COLUMN `Floodgate` INTEGER(3)";
|
||||
|
||||
protected static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE
|
||||
+ "` WHERE `Name`=? LIMIT 1";
|
||||
protected static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE
|
||||
+ "` WHERE `UUID`=? LIMIT 1";
|
||||
protected static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE + "` WHERE `Name`=? LIMIT 1";
|
||||
protected static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE + "` WHERE `UUID`=? LIMIT 1";
|
||||
protected static final String INSERT_PROFILE = "INSERT INTO `" + PREMIUM_TABLE
|
||||
+ "` (`UUID`, `Name`, `Premium`, `Floodgate`, `LastIp`) " + "VALUES (?, ?, ?, ?, ?) ";
|
||||
+ "` (`UUID`, `Name`, `Premium`, `LastIp`) " + "VALUES (?, ?, ?, ?) ";
|
||||
// limit not necessary here, because it's unique
|
||||
protected static final String UPDATE_PROFILE = "UPDATE `" + PREMIUM_TABLE
|
||||
+ "` SET `UUID`=?, `Name`=?, `Premium`=?, `Floodgate`=?, `LastIp`=?, "
|
||||
+ "`LastLogin`=CURRENT_TIMESTAMP WHERE `UserID`=?";
|
||||
+ "` SET `UUID`=?, `Name`=?, `Premium`=?, `LastIp`=?, `LastLogin`=CURRENT_TIMESTAMP WHERE `UserID`=?";
|
||||
|
||||
protected final Logger log;
|
||||
protected final HikariDataSource dataSource;
|
||||
@@ -89,23 +81,11 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
// choose surrogate PK(ID), because UUID can be null for offline players
|
||||
// if UUID is always Premium UUID we would have to update offline player entries on insert
|
||||
// name cannot be PK, because it can be changed for premium players
|
||||
|
||||
//todo: add unique uuid index usage
|
||||
try (Connection con = dataSource.getConnection();
|
||||
Statement stmt = con.createStatement()) {
|
||||
stmt.executeUpdate(getCreateTableStmt());
|
||||
|
||||
// add Floodgate column
|
||||
DatabaseMetaData md = con.getMetaData();
|
||||
if (isColumnMissing(md, "Floodgate")) {
|
||||
stmt.executeUpdate(ADD_FLOODGATE_COLUMN_STMT);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
|
||||
try (ResultSet rs = metaData.getColumns(null, null, PREMIUM_TABLE, columnName)) {
|
||||
return !rs.next();
|
||||
Statement createStmt = con.createStatement()) {
|
||||
createStmt.executeUpdate(CREATE_TABLE_STMT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +97,7 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
loadStmt.setString(1, name);
|
||||
|
||||
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
||||
return parseResult(resultSet).orElseGet(() -> new StoredProfile(null, name, false,
|
||||
FloodgateState.FALSE, ""));
|
||||
return parseResult(resultSet).orElseGet(() -> new StoredProfile(null, name, false, ""));
|
||||
}
|
||||
} catch (SQLException sqlEx) {
|
||||
log.error("Failed to query profile: {}", name, sqlEx);
|
||||
@@ -145,25 +124,15 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
|
||||
private Optional<StoredProfile> parseResult(ResultSet resultSet) throws SQLException {
|
||||
if (resultSet.next()) {
|
||||
long userId = resultSet.getInt("UserID");
|
||||
long userId = resultSet.getInt(1);
|
||||
|
||||
UUID uuid = Optional.ofNullable(resultSet.getString("UUID")).map(UUIDAdapter::parseId).orElse(null);
|
||||
UUID uuid = Optional.ofNullable(resultSet.getString(2)).map(UUIDAdapter::parseId).orElse(null);
|
||||
|
||||
String name = resultSet.getString("Name");
|
||||
boolean premium = resultSet.getBoolean("Premium");
|
||||
int floodgateNum = resultSet.getInt("Floodgate");
|
||||
FloodgateState floodgate;
|
||||
|
||||
// if the player wasn't migrated to the new database format
|
||||
if (resultSet.wasNull()) {
|
||||
floodgate = FloodgateState.NOT_MIGRATED;
|
||||
} else {
|
||||
floodgate = FloodgateState.fromInt(floodgateNum);
|
||||
}
|
||||
|
||||
String lastIp = resultSet.getString("LastIp");
|
||||
Instant lastLogin = resultSet.getTimestamp("LastLogin").toInstant();
|
||||
return Optional.of(new StoredProfile(userId, uuid, name, premium, floodgate, lastIp, lastLogin));
|
||||
String name = resultSet.getString(3);
|
||||
boolean premium = resultSet.getBoolean(4);
|
||||
String lastIp = resultSet.getString(5);
|
||||
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
||||
return Optional.of(new StoredProfile(userId, uuid, name, premium, lastIp, lastLogin));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
@@ -181,10 +150,9 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
saveStmt.setString(1, uuid);
|
||||
saveStmt.setString(2, playerProfile.getName());
|
||||
saveStmt.setBoolean(3, playerProfile.isPremium());
|
||||
saveStmt.setInt(4, playerProfile.getFloodgate().getValue());
|
||||
saveStmt.setString(5, playerProfile.getLastIp());
|
||||
saveStmt.setString(4, playerProfile.getLastIp());
|
||||
|
||||
saveStmt.setLong(6, playerProfile.getRowId());
|
||||
saveStmt.setLong(5, playerProfile.getRowId());
|
||||
saveStmt.execute();
|
||||
}
|
||||
} else {
|
||||
@@ -193,9 +161,7 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
|
||||
saveStmt.setString(2, playerProfile.getName());
|
||||
saveStmt.setBoolean(3, playerProfile.isPremium());
|
||||
saveStmt.setBoolean(3, playerProfile.isPremium());
|
||||
saveStmt.setInt(4, playerProfile.getFloodgate().getValue());
|
||||
saveStmt.setString(5, playerProfile.getLastIp());
|
||||
saveStmt.setString(4, playerProfile.getLastIp());
|
||||
|
||||
saveStmt.execute();
|
||||
try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
|
||||
@@ -213,14 +179,6 @@ public abstract class SQLStorage implements AuthStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SQLite has a slightly different syntax, so this will be overridden by SQLiteStorage
|
||||
* @return An SQL Statement to create the `premium` table
|
||||
*/
|
||||
protected String getCreateTableStmt() {
|
||||
return CREATE_TABLE_STMT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
dataSource.close();
|
||||
|
||||
@@ -31,23 +31,15 @@ import org.sqlite.JDBC;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class SQLiteStorage extends SQLStorage {
|
||||
|
||||
protected static final String CREATE_TABLE_STMT = "CREATE TABLE IF NOT EXISTS `" + PREMIUM_TABLE + "` ("
|
||||
+ "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, "
|
||||
+ "`UUID` CHAR(36), "
|
||||
+ "`Name` VARCHAR(16) NOT NULL, "
|
||||
+ "`Premium` BOOLEAN NOT NULL, "
|
||||
+ "`LastIp` VARCHAR(255) NOT NULL, "
|
||||
+ "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
|
||||
//the premium shouldn't steal the cracked account by changing the name
|
||||
+ "UNIQUE (`Name`) "
|
||||
+ ')';
|
||||
|
||||
private static final String SQLITE_DRIVER = "org.sqlite.SQLiteDataSource";
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
@@ -111,9 +103,12 @@ public class SQLiteStorage extends SQLStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateTableStmt() {
|
||||
// SQLite has a different syntax for auto increment
|
||||
return CREATE_TABLE_STMT.replace("AUTO_INCREMENT", "AUTOINCREMENT");
|
||||
public void createTables() throws SQLException {
|
||||
try (Connection con = dataSource.getConnection();
|
||||
Statement createStmt = con.createStatement()) {
|
||||
// SQLite has a different syntax for auto increment
|
||||
createStmt.executeUpdate(CREATE_TABLE_STMT.replace("AUTO_INCREMENT", "AUTOINCREMENT"));
|
||||
}
|
||||
}
|
||||
|
||||
private static String replacePathVariables(Path dataFolder, String input) {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
package com.github.games647.fastlogin.core.storage;
|
||||
|
||||
import com.github.games647.craftapi.model.Profile;
|
||||
import com.github.games647.fastlogin.core.shared.FloodgateState;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
@@ -40,28 +39,20 @@ public class StoredProfile extends Profile {
|
||||
private final ReentrantLock saveLock = new ReentrantLock();
|
||||
|
||||
private boolean premium;
|
||||
private FloodgateState floodgate;
|
||||
private String lastIp;
|
||||
private Instant lastLogin;
|
||||
|
||||
public StoredProfile(long rowId, UUID uuid, String playerName, boolean premium, FloodgateState floodgate,
|
||||
String lastIp, Instant lastLogin) {
|
||||
public StoredProfile(long rowId, UUID uuid, String playerName, boolean premium, String lastIp, Instant lastLogin) {
|
||||
super(uuid, playerName);
|
||||
|
||||
this.rowId = rowId;
|
||||
this.premium = premium;
|
||||
this.floodgate = floodgate;
|
||||
this.lastIp = lastIp;
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
|
||||
public StoredProfile(UUID uuid, String playerName, boolean premium, FloodgateState isFloodgate, String lastIp) {
|
||||
this(-1, uuid, playerName, premium, isFloodgate, lastIp, Instant.now());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public StoredProfile(UUID uuid, String playerName, boolean premium, String lastIp) {
|
||||
this(-1, uuid, playerName, premium, FloodgateState.FALSE, lastIp, Instant.now());
|
||||
this(-1, uuid, playerName, premium, lastIp, Instant.now());
|
||||
}
|
||||
|
||||
public ReentrantLock getSaveLock() {
|
||||
@@ -105,18 +96,6 @@ public class StoredProfile extends Profile {
|
||||
this.premium = premium;
|
||||
}
|
||||
|
||||
public synchronized FloodgateState getFloodgate() {
|
||||
return floodgate;
|
||||
}
|
||||
|
||||
public synchronized boolean isFloodgateMigrated() {
|
||||
return floodgate != FloodgateState.NOT_MIGRATED;
|
||||
}
|
||||
|
||||
public synchronized void setFloodgate(FloodgateState floodgate) {
|
||||
this.floodgate = floodgate;
|
||||
}
|
||||
|
||||
public synchronized String getLastIp() {
|
||||
return lastIp;
|
||||
}
|
||||
@@ -149,7 +128,7 @@ public class StoredProfile extends Profile {
|
||||
}
|
||||
|
||||
return rowId == that.rowId && premium == that.premium
|
||||
&& Objects.equals(lastIp, that.lastIp) && lastLogin.equals(that.lastLogin);
|
||||
&& Objects.equals(lastIp, that.lastIp) && lastLogin.equals(that.lastLogin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,7 +141,6 @@ public class StoredProfile extends Profile {
|
||||
return this.getClass().getSimpleName() + '{'
|
||||
+ "rowId=" + rowId
|
||||
+ ", premium=" + premium
|
||||
+ ", floodgate=" + floodgate
|
||||
+ ", lastIp='" + lastIp + '\''
|
||||
+ ", lastLogin=" + lastLogin
|
||||
+ "} " + super.toString();
|
||||
|
||||
@@ -70,7 +70,7 @@ no-console: '&4You are not a player. You cannot toggle the premium state for YOU
|
||||
|
||||
# The user wants to toggle premium state, but BungeeCord support is enabled. This means the server have to communicate
|
||||
# with the BungeeCord first which will establish a connection with the database server.
|
||||
wait-on-proxy: '&6Sending request... (Do not forget to follow the BungeeCord setup guide referenced on the plugin page)'
|
||||
wait-on-proxy: '&6Sending request... (Do not forget to follow the BungeeCord setup guide)'
|
||||
|
||||
# When ProtocolLib is enabled and the plugin is unable to continue handling a login request after a requested premium
|
||||
# authentication. In this state the client expects a success packet with an encrypted connection or disconnect packet.
|
||||
@@ -100,3 +100,5 @@ Type &a/premium&6 again to confirm'
|
||||
invalid-public-key: '&cInvalid client public key. Please try to restart your game.'
|
||||
|
||||
# ========= Bungee/Waterfall only ================================
|
||||
|
||||
|
||||
|
||||
17
pom.xml
17
pom.xml
@@ -103,7 +103,7 @@
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>4.3</version>
|
||||
<version>4.1</version>
|
||||
<configuration>
|
||||
<licenseSets>
|
||||
<licenseSet>
|
||||
@@ -115,7 +115,6 @@
|
||||
<excludes>
|
||||
<exclude>src/test/resources/**</exclude>
|
||||
<exclude>src/main/resources/**</exclude>
|
||||
<exclude>.java-version</exclude>
|
||||
</excludes>
|
||||
</licenseSet>
|
||||
</licenseSets>
|
||||
@@ -131,7 +130,7 @@
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<configLocation>checkstyle.xml</configLocation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
@@ -142,7 +141,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.12.7</version>
|
||||
<version>10.9.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -159,7 +158,7 @@
|
||||
<!-- Require newer versions for Junit5 support -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
@@ -188,22 +187,22 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
<version>1.18.26</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<version>5.9.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Require inline to support static mocks -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.9.0</version>
|
||||
<artifactId>mockito-inline</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>templating-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>1.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>filter-src</id>
|
||||
@@ -67,7 +67,7 @@
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
|
||||
@@ -97,10 +97,6 @@
|
||||
<exclude>com.google.guava:guava</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
@@ -133,10 +129,6 @@
|
||||
<id>velocity</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>opencollab-snapshot</id>
|
||||
<url>https://repo.opencollab.dev/main/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -151,7 +143,7 @@
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -159,29 +151,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Bedrock player bridge -->
|
||||
<dependency>
|
||||
<groupId>org.geysermc.geyser</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${geyser.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Floodgate -->
|
||||
<dependency>
|
||||
<groupId>org.geysermc.floodgate</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${floodgate.version}</version>
|
||||
<scope>provided</scope>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -27,8 +27,6 @@ package com.github.games647.fastlogin.velocity;
|
||||
|
||||
import com.github.games647.fastlogin.core.AsyncScheduler;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.BedrockService;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.GeyserService;
|
||||
import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
|
||||
import com.github.games647.fastlogin.core.message.ChannelMessage;
|
||||
import com.github.games647.fastlogin.core.message.SuccessMessage;
|
||||
@@ -52,8 +50,6 @@ import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -80,8 +76,6 @@ public class FastLoginVelocity implements PlatformPlugin<CommandSource> {
|
||||
|
||||
private FastLoginCore<Player, CommandSource, FastLoginVelocity> core;
|
||||
private AsyncScheduler scheduler;
|
||||
private FloodgateService floodgateService;
|
||||
private GeyserService geyserService;
|
||||
private UUID proxyId;
|
||||
|
||||
@Inject
|
||||
@@ -101,14 +95,6 @@ public class FastLoginVelocity implements PlatformPlugin<CommandSource> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPluginInstalled("floodgate")) {
|
||||
floodgateService = new FloodgateService(FloodgateApi.getInstance(), core);
|
||||
}
|
||||
|
||||
if (isPluginInstalled("Geyser-Velocity")) {
|
||||
geyserService = new GeyserService(GeyserImpl.getInstance(), core);
|
||||
}
|
||||
|
||||
server.getEventManager().register(this, new ConnectListener(this, core.getAntiBot()));
|
||||
server.getEventManager().register(this, new PluginMessageListener(this));
|
||||
|
||||
@@ -154,21 +140,9 @@ public class FastLoginVelocity implements PlatformPlugin<CommandSource> {
|
||||
return server.getPluginManager().isLoaded(name);
|
||||
}
|
||||
|
||||
public FloodgateService getFloodgateService() {
|
||||
return floodgateService;
|
||||
}
|
||||
|
||||
public GeyserService getGeyserService() {
|
||||
return geyserService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockService<?> getBedrockService() {
|
||||
if (floodgateService != null) {
|
||||
return floodgateService;
|
||||
}
|
||||
|
||||
return geyserService;
|
||||
return null;
|
||||
}
|
||||
|
||||
public FastLoginCore<Player, CommandSource, FastLoginVelocity> getCore() {
|
||||
|
||||
@@ -53,12 +53,10 @@ public class VelocityLoginSource implements LoginSource {
|
||||
public void kick(String message) {
|
||||
if (message == null) {
|
||||
preLoginEvent.setResult(PreLoginEvent.PreLoginComponentResult.denied(
|
||||
Component.text("Kicked").color(NamedTextColor.WHITE))
|
||||
);
|
||||
Component.text("Kicked").color(NamedTextColor.WHITE)));
|
||||
} else {
|
||||
preLoginEvent.setResult(PreLoginEvent.PreLoginComponentResult.denied(
|
||||
LegacyComponentSerializer.legacyAmpersand().deserialize(message))
|
||||
);
|
||||
LegacyComponentSerializer.legacyAmpersand().deserialize(message)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,15 +28,13 @@ package com.github.games647.fastlogin.velocity.listener;
|
||||
import com.github.games647.craftapi.UUIDAdapter;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import com.github.games647.fastlogin.core.shared.LoginSession;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
import com.github.games647.fastlogin.velocity.FastLoginVelocity;
|
||||
import com.github.games647.fastlogin.velocity.VelocityLoginSession;
|
||||
import com.github.games647.fastlogin.velocity.task.AsyncPremiumCheck;
|
||||
import com.github.games647.fastlogin.velocity.task.FloodgateAuthTask;
|
||||
import com.github.games647.fastlogin.velocity.task.ForceLoginTask;
|
||||
import com.velocitypowered.api.event.EventTask;
|
||||
import com.velocitypowered.api.event.Continuation;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.connection.PreLoginEvent;
|
||||
@@ -50,7 +48,6 @@ import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.util.GameProfile.Property;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
@@ -70,9 +67,9 @@ public class ConnectListener {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public EventTask onPreLogin(PreLoginEvent preLoginEvent) {
|
||||
public void onPreLogin(PreLoginEvent preLoginEvent, Continuation continuation) {
|
||||
if (!preLoginEvent.getResult().isAllowed()) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
InboundConnection connection = preLoginEvent.getConnection();
|
||||
@@ -84,30 +81,28 @@ public class ConnectListener {
|
||||
switch (action) {
|
||||
case Ignore:
|
||||
// just ignore
|
||||
return null;
|
||||
return;
|
||||
case Block:
|
||||
String message = plugin.getCore().getMessage("kick-antibot");
|
||||
TextComponent messageParsed = LegacyComponentSerializer.legacyAmpersand().deserialize(message);
|
||||
|
||||
PreLoginComponentResult reason = PreLoginComponentResult.denied(messageParsed);
|
||||
preLoginEvent.setResult(reason);
|
||||
return null;
|
||||
break;
|
||||
case Continue:
|
||||
default:
|
||||
return EventTask.async(
|
||||
new AsyncPremiumCheck(plugin, connection, username, preLoginEvent)
|
||||
Runnable asyncPremiumCheck = new AsyncPremiumCheck(
|
||||
plugin, connection, username, continuation, preLoginEvent
|
||||
);
|
||||
plugin.getScheduler().runAsync(asyncPremiumCheck);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameProfileRequest(GameProfileRequestEvent event) {
|
||||
public void onGameprofileRequest(GameProfileRequestEvent event) {
|
||||
if (event.isOnlineMode()) {
|
||||
LoginSession session = plugin.getSession().get(event.getConnection().getRemoteAddress());
|
||||
if (session == null) {
|
||||
plugin.getLog().warn("No active login session found for player {}", event.getUsername());
|
||||
return;
|
||||
}
|
||||
|
||||
UUID verifiedUUID = event.getGameProfile().getId();
|
||||
String verifiedUsername = event.getUsername();
|
||||
@@ -146,20 +141,8 @@ public class ConnectListener {
|
||||
Player player = serverConnectedEvent.getPlayer();
|
||||
RegisteredServer server = serverConnectedEvent.getServer();
|
||||
|
||||
FloodgateService floodgateService = plugin.getFloodgateService();
|
||||
if (floodgateService != null) {
|
||||
FloodgatePlayer floodgatePlayer = floodgateService.getBedrockPlayer(player.getUniqueId());
|
||||
if (floodgatePlayer != null) {
|
||||
plugin.getLog().info("Running floodgate handling for {}", player);
|
||||
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer, server);
|
||||
plugin.getScheduler().runAsync(floodgateAuthTask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VelocityLoginSession session = plugin.getSession().get(player.getRemoteAddress());
|
||||
if (session == null) {
|
||||
plugin.getLog().info("No active login session found on server connect for {}", player);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -168,7 +151,7 @@ public class ConnectListener {
|
||||
// player is still in the login phase and reported to be offline.
|
||||
Runnable loginTask = new ForceLoginTask(plugin.getCore(), player, server, session);
|
||||
plugin.getProxy().getScheduler()
|
||||
.buildTask(plugin, loginTask)
|
||||
.buildTask(plugin, () -> plugin.getScheduler().runAsync(loginTask))
|
||||
.delay(1L, TimeUnit.SECONDS) // Delay at least one second, otherwise the login command can be missed
|
||||
.schedule();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
|
||||
import com.github.games647.fastlogin.core.message.SuccessMessage;
|
||||
import com.github.games647.fastlogin.core.shared.FastLoginCore;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import com.github.games647.fastlogin.velocity.FastLoginVelocity;
|
||||
import com.github.games647.fastlogin.velocity.VelocityLoginSession;
|
||||
import com.github.games647.fastlogin.velocity.task.AsyncToggleMessage;
|
||||
@@ -116,15 +115,7 @@ public class PluginMessageListener {
|
||||
}
|
||||
|
||||
private void onSuccessMessage(Player forPlayer) {
|
||||
boolean shouldPersist = forPlayer.isOnlineMode();
|
||||
|
||||
FloodgateService floodgateService = plugin.getFloodgateService();
|
||||
if (!shouldPersist && floodgateService != null) {
|
||||
// always save floodgate players to lock this username
|
||||
shouldPersist = floodgateService.isBedrockPlayer(forPlayer.getUniqueId());
|
||||
}
|
||||
|
||||
if (shouldPersist) {
|
||||
if (forPlayer.isOnlineMode()) {
|
||||
//bukkit module successfully received and force logged in the user
|
||||
//update only on success to prevent corrupt data
|
||||
VelocityLoginSession loginSession = plugin.getSession().get(forPlayer.getRemoteAddress());
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.github.games647.fastlogin.velocity.VelocityLoginSession;
|
||||
import com.github.games647.fastlogin.velocity.VelocityLoginSource;
|
||||
import com.github.games647.fastlogin.velocity.event.VelocityFastLoginPreLoginEvent;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.Continuation;
|
||||
import com.velocitypowered.api.event.connection.PreLoginEvent;
|
||||
import com.velocitypowered.api.proxy.InboundConnection;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
@@ -44,22 +45,28 @@ public class AsyncPremiumCheck extends JoinManagement<Player, CommandSource, Vel
|
||||
|
||||
private final FastLoginVelocity plugin;
|
||||
private final String username;
|
||||
private final Continuation continuation;
|
||||
private final PreLoginEvent preLoginEvent;
|
||||
private final InboundConnection connection;
|
||||
|
||||
public AsyncPremiumCheck(FastLoginVelocity plugin, InboundConnection connection, String username,
|
||||
PreLoginEvent preLoginEvent) {
|
||||
Continuation continuation, PreLoginEvent preLoginEvent) {
|
||||
super(plugin.getCore(), plugin.getCore().getAuthPluginHook(), plugin.getBedrockService());
|
||||
this.plugin = plugin;
|
||||
this.connection = connection;
|
||||
this.username = username;
|
||||
this.continuation = continuation;
|
||||
this.preLoginEvent = preLoginEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
plugin.getSession().remove(connection.getRemoteAddress());
|
||||
super.onLogin(username, new VelocityLoginSource(connection, preLoginEvent));
|
||||
try {
|
||||
super.onLogin(username, new VelocityLoginSource(connection, preLoginEvent));
|
||||
} finally {
|
||||
continuation.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 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.velocity.task;
|
||||
|
||||
import com.github.games647.fastlogin.core.shared.FastLoginCore;
|
||||
import com.github.games647.fastlogin.core.shared.FloodgateManagement;
|
||||
import com.github.games647.fastlogin.velocity.FastLoginVelocity;
|
||||
import com.github.games647.fastlogin.velocity.VelocityLoginSession;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FloodgateAuthTask
|
||||
extends FloodgateManagement<Player, CommandSource, VelocityLoginSession, FastLoginVelocity> {
|
||||
|
||||
private final RegisteredServer server;
|
||||
|
||||
public FloodgateAuthTask(FastLoginCore<Player, CommandSource, FastLoginVelocity> core, Player player,
|
||||
FloodgatePlayer floodgatePlayer, RegisteredServer server) {
|
||||
super(core, player, floodgatePlayer);
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startLogin() {
|
||||
VelocityLoginSession session = new VelocityLoginSession(player.getUsername(), isRegistered, profile);
|
||||
core.getPlugin().getSession().put(player.getRemoteAddress(), session);
|
||||
|
||||
// enable auto login based on the value of 'autoLoginFloodgate' in config.yml
|
||||
boolean forcedOnlineMode = autoLoginFloodgate.equals("true")
|
||||
|| (autoLoginFloodgate.equals("linked") && isLinked);
|
||||
|
||||
// delay sending force command, because Paper will process the login event asynchronously
|
||||
// In this case it means that the force command (plugin message) is already received and processed while
|
||||
// player is still in the login phase and reported to be offline.
|
||||
Runnable loginTask = new ForceLoginTask(core.getPlugin().getCore(), player, server, session, forcedOnlineMode);
|
||||
core.getPlugin().getProxy().getScheduler()
|
||||
.buildTask(core.getPlugin(), () -> core.getPlugin().getScheduler().runAsync(loginTask))
|
||||
.delay(1L, TimeUnit.SECONDS) // Delay at least one second, otherwise the login command can be missed
|
||||
.schedule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(Player player) {
|
||||
return player.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUUID(Player player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetSocketAddress getAddress(Player player) {
|
||||
return player.getRemoteAddress();
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,6 @@ public class ForceLoginTask
|
||||
@Override
|
||||
public void run() {
|
||||
if (session == null) {
|
||||
core.getPlugin().getLog().info("No active login session on force handling for {}", player);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,7 +80,6 @@ public class ForceLoginTask
|
||||
@Override
|
||||
public boolean forceLogin(Player player) {
|
||||
if (session.isAlreadyLogged()) {
|
||||
core.getPlugin().getLog().info("Ignoring second force login attempt for {}", player);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,11 +92,11 @@ public class ForceLoginTask
|
||||
VelocityFastLoginAutoLoginEvent event = new VelocityFastLoginAutoLoginEvent(session, profile);
|
||||
try {
|
||||
return core.getPlugin().getProxy().getEventManager().fire(event).get();
|
||||
} catch (InterruptedException interruptedEx) {
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt(); // Set the interrupt flag again
|
||||
return event;
|
||||
} catch (ExecutionException executionEx) {
|
||||
core.getPlugin().getLog().error("Error firing event", executionEx);
|
||||
} catch (ExecutionException e) {
|
||||
core.getPlugin().getLog().error("Error firing event", e);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
@@ -116,8 +114,6 @@ public class ForceLoginTask
|
||||
type = Type.REGISTER;
|
||||
}
|
||||
|
||||
core.getPlugin().getLog().info("Sending force {} for {} towards server {}", type, player.getUsername(), server);
|
||||
|
||||
UUID proxyId = core.getPlugin().getProxyId();
|
||||
ChannelMessage loginMessage = new LoginActionMessage(type, player.getUsername(), proxyId);
|
||||
core.getPlugin().sendPluginMessage(server, loginMessage);
|
||||
|
||||
Reference in New Issue
Block a user