Compare commits

..

2 Commits

Author SHA1 Message Date
games647
44abe78213 Re-enable papermc release repo 2023-05-22 15:11:39 +02:00
games647
6f69f73bad Include updated yaml for older Spigot platforms
Fixes #1031
2023-05-22 15:08:12 +02:00
133 changed files with 822 additions and 2189 deletions

View File

@@ -12,6 +12,10 @@ body:
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
@@ -32,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
@@ -55,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

View 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.)

View File

@@ -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

View File

@@ -10,23 +10,7 @@ updates:
interval: "monthly"
# Maven project
- package-ecosystem: "maven"
- package-ecosystem: maven
directory: "/"
schedule:
interval: "monthly"
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"]
interval: weekly

25
.github/release.yml vendored
View File

@@ -1,25 +0,0 @@
# Configure how the release notes are generated for GitHub releases
changelog:
# List of authors (like bots) and labels to exclude from pull requests
exclude:
labels:
- ignore-for-release
categories:
- title: 🛠 Breaking Changes
labels:
- Semver-Major
- breaking-change
- title: 🎉 Exciting New Features
labels:
- Semver-Minor
- enhancement
- title: 🐞 Bugfixes
labels:
- bug
- title: 👒 Dependencies
labels:
- dependencies
- title: Other Changes
labels:
- "*"

View File

@@ -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,12 +20,9 @@ jobs:
# Environment
runs-on: ubuntu-latest
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
# Only allow write for security, then all others default to read only
actions: read
contents: read
security-events: write
strategy:
@@ -36,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@v5
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}}"

View File

@@ -21,20 +21,19 @@ jobs:
# Environment image - always use the newest OS
runs-on: ubuntu-latest
permissions:
# With at least one permission given, all default to read
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@v5
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version-file: '.java-version'
java-version: 19
cache: 'maven'
# Build and test (included in package)
@@ -42,26 +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
dependency:
runs-on: ubuntu-latest
permissions:
# Write only necessary for dependency submission all others then default to read
contents: write
# Run steps
steps:
# Pull changes
- uses: actions/checkout@v4
# Setup Java
- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version-file: '.java-version'
cache: 'maven'
- name: Submit Dependency Snapshot
if: ${{ github.event_name == 'push' }}
uses: advanced-security/maven-dependency-submission-action@v5.0.0

View File

@@ -1,2 +0,0 @@
# Latest GitHub Action java release that is installed on the runners
21

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015-2024 games647 and contributors
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

View File

@@ -1,7 +1,5 @@
# FastLogin
![A shield-shaped emblem with a bold lightning bolt on the left, resembling Minecraft blocks. To the right, "FastLogin" is written in teal, with the tagline: "Automatically detect and login premium Minecraft players"](https://github.com/user-attachments/assets/0788ef69-029b-465e-83a2-b8e7bccc6295 "FastLogin project logo.avif")
Checks if a Minecraft player has a paid account (premium). If so, they can skip offline authentication (auth plugins).
So they don't need to enter passwords. This is also called auto login (auto-login).
@@ -10,11 +8,14 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
* Detect paid accounts from others
* Automatically login paid accounts (premium)
* Support various of auth plugins
* Cauldron support
* Forge/Sponge message support
* Premium UUID support
* Forward skins
* Detect username changed and will update the existing database record
* BungeeCord/Velocity support
* BungeeCord support
* Auto register new premium players
* Plugin: ProtocolSupport is supported and can be used as an alternative to ProtocolLib
* No client modifications needed
* Good performance by using async operations
* Locale messages
@@ -32,11 +33,7 @@ Development builds contain the latest changes from the Source-Code. They are ble
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.
~~You can download them from here: [CodeMC(Jenkins)](https://ci.codemc.org/job/Games647/job/FastLogin/)~~
Currently broken due changed usernames. Download it from [here](https://github.com/TuxCoding/FastLogin/releases)
You can download them from here: https://ci.codemc.org/job/Games647/job/FastLogin/
***
@@ -49,7 +46,6 @@ Currently broken due changed usernames. Download it from [here](https://github.c
fastlogin.bukkit.command.premium
fastlogin.bukkit.command.cracked
fastlogin.command.premium.other
fastlogin.command.cracked.other
@@ -64,15 +60,13 @@ Possible values: `Premium`, `Cracked`, `Unknown`
## Requirements
* Java: 21+ recommended for improved multi-threading code by FastLogin
* Spigot: 8+
* BungeeCord and Velocity: 17+
* Java 17+
* Server software in offlinemode:
* Spigot (or a fork e.g. Paper) 1.8.8+
* Protocol plugin:
* [ProtocolLib 5.3+ with development build above 720](https://www.spigotmc.org/resources/protocollib.1997/) or
* [ProtocolLib 5.0+](https://www.spigotmc.org/resources/protocollib.1997/) or
* [ProtocolSupport](https://www.spigotmc.org/resources/protocolsupport.7201/)
* Latest BungeeCord (or a fork e.g. Waterfall) or Velocity proxy
* Latest BungeeCord (or a fork e.g. Waterfall)
* An auth plugin.
### Supported auth plugins
@@ -91,6 +85,7 @@ Possible values: `Premium`, `Cracked`, `Unknown`
#### BungeeCord/Waterfall
* [BungeeAuth](https://www.spigotmc.org/resources/bungeeauth.493/)
* [BungeeAuthenticator](https://www.spigotmc.org/resources/bungeecordauthenticator.87669/)
## Network requests
@@ -106,8 +101,8 @@ This plugin performs network requests to:
### Spigot/Paper
1. Download and install ProtocolLib/ProtocolSupport
2. Download and install `FastLoginBukkit`
3. Set your server in offline mode by setting the value `onlinemode` in your server.properties to `false`
2. Download and install FastLogin (or `FastLoginBukkit` for newer versions)
3. Set your server in offline mode by setting the value `onlinemode` in your server.properties to false
### BungeeCord/Waterfall or Velocity
@@ -122,8 +117,8 @@ Install the plugin on both platforms, that is proxy (BungeeCord or Velocity) and
4. Activate ip forwarding in your proxy config
5. Check your database settings in the config of FastLogin on your proxy
* The proxies only ship with a limited set of drivers where Spigot supports more. Therefore, these are supported:
* BungeeCord: `mysql` for MySQL/MariaDB
* Velocity: `mariadb` for MySQL/MariaDB
* BungeeCord: `com.mysql.jdbc.Driver` for MySQL/MariaDB
* Velocity: `fastlogin.mariadb.jdbc.Driver` for MySQL/MariaDB
* Note the embedded file storage SQLite is not available
* MySQL/MariaDB requires an external database server running. Check your server provider if there is one available
or install one.

View File

@@ -4,7 +4,7 @@
The MIT License (MIT)
Copyright (c) 2015-2024 games647 and contributors
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
@@ -30,7 +30,7 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.release>8</maven.compiler.release>
<nettyVersion>4.1.79.Final</nettyVersion>
</properties>
<parent>
@@ -50,7 +50,7 @@
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<version>3.4.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>false</shadedArtifactAttached>
@@ -98,6 +98,7 @@
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
<exclude>**/module-info.class</exclude>
</excludes>
</filter>
@@ -116,16 +117,19 @@
</build>
<repositories>
<!-- PaperSpigot API, PaperLib, datafixupper and bungeecord-chat -->
<!-- PaperSpigot API and PaperLib -->
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
<!-- ProtocolLib -->
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<!-- AuthMe Reloaded, xAuth and LoginSecurity -->
@@ -164,11 +168,18 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
<scope>compile</scope>
</dependency>
<!-- PaperSpigot API for correcting user cache usage -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.6-R0.1-SNAPSHOT</version>
<version>1.19-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<!-- Use our own newer api version -->
<exclusions>
@@ -176,25 +187,13 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>datafixerupper</artifactId>
<version>7.1.15</version>
<version>5.0.28</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -208,7 +207,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>5.3.0</version>
<version>5.0.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -279,7 +278,7 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.6</version>
<version>2.11.3</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
@@ -294,7 +293,7 @@
<dependency>
<groupId>fr.xephi</groupId>
<artifactId>authme</artifactId>
<version>5.6.0</version>
<version>5.6.0-beta2</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
@@ -308,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>
@@ -348,22 +347,6 @@
</exclusions>
</dependency>
<dependency>
<groupId>com.github.zigazajc007</groupId>
<artifactId>Passky</artifactId>
<version>v3.0.0</version>
<scope>provided</scope>
<optional>true</optional>
<!-- Exclude dependencies to prevent potential version conflicts-->
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--No maven repository :(-->
<dependency>
<groupId>de.st_ddt.crazy</groupId>
@@ -395,7 +378,29 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.80</version>
<version>1.72</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${nettyVersion}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>${nettyVersion}</version>
<scope>test</scope>
</dependency>
<!-- Provided by the spigot, required for testing ProtocolLib -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -47,6 +47,7 @@ public class BukkitLoginSession extends LoginSession {
private final ClientPublicKey clientPublicKey;
private boolean verified;
private SkinProperty skinProperty;
public BukkitLoginSession(String username, byte[] verifyToken, ClientPublicKey publicKey, boolean registered,
@@ -108,7 +109,7 @@ public class BukkitLoginSession extends LoginSession {
*
* @param verified whether the player has valid session
*/
public synchronized void setVerifiedPremium(boolean verified) {
public synchronized void setVerified(boolean verified) {
this.verified = verified;
}
@@ -117,7 +118,7 @@ public class BukkitLoginSession extends LoginSession {
*
* @return whether the player has a valid session
*/
public synchronized boolean isVerifiedPremium() {
public synchronized boolean isVerified() {
return verified;
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -25,7 +25,7 @@
*/
package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.core.scheduler.AsyncScheduler;
import com.github.games647.fastlogin.core.AsyncScheduler;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.slf4j.Logger;
@@ -39,7 +39,7 @@ public class BukkitScheduler extends AsyncScheduler {
public BukkitScheduler(Plugin plugin, Logger logger) {
super(logger, command -> Bukkit.getScheduler().runTaskAsynchronously(plugin, command));
syncExecutor = task -> Bukkit.getScheduler().runTask(plugin, task);
syncExecutor = r -> Bukkit.getScheduler().runTask(plugin, r);
}
public Executor getSyncExecutor() {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -31,7 +31,6 @@ import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import io.papermc.paper.configuration.ServerConfiguration;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.entity.Player;
@@ -134,13 +133,6 @@ public class BungeeManager {
}
private boolean detectProxy() {
try {
ServerConfiguration.class.getDeclaredMethod("isProxyEnabled");
return Bukkit.getServerConfig().isProxyEnabled();
} catch (NoClassDefFoundError | NoSuchMethodException noSuchClassMethodEx) {
// Ignore continue below
}
try {
if (isProxySupported("org.spigotmc.SpigotConfig", "bungee")) {
return true;

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -28,7 +28,6 @@ package com.github.games647.fastlogin.bukkit;
import com.comphenix.protocol.ProtocolLibrary;
import com.github.games647.fastlogin.bukkit.command.CrackedCommand;
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
import com.github.games647.fastlogin.bukkit.command.DeleteCommand;
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
import com.github.games647.fastlogin.bukkit.listener.PaperCacheListener;
import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener;
@@ -37,7 +36,6 @@ import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSup
import com.github.games647.fastlogin.bukkit.task.DelayedAuthHook;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
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;
@@ -55,7 +53,6 @@ import org.slf4j.Logger;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@@ -68,10 +65,7 @@ import java.util.concurrent.ConcurrentMap;
public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<CommandSender> {
//1 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang)
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(
Duration.ofMinutes(1), -1
);
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(1, -1);
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
private final Logger logger;
@@ -117,11 +111,10 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
return;
}
AntiBotService antiBotService = core.getAntiBotService();
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
pluginManager.registerEvents(new ProtocolSupportListener(this, antiBotService), this);
pluginManager.registerEvents(new ProtocolSupportListener(this, core.getAntiBot()), this);
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
ProtocolLibListener.register(this, antiBotService, core.getConfig().getBoolean("verifyClientKeys"));
ProtocolLibListener.register(this, core.getAntiBot(), core.getConfig().getBoolean("verifyClientKeys"));
//if server is using paper - we need to set the skin at pre login anyway, so no need for this listener
if (!isPaper() && getConfig().getBoolean("forwardSkin")) {
@@ -144,7 +137,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
pluginManager.registerEvents(new PaperCacheListener(this), this);
}
registerCommands();
//register commands using a unique name
Optional.ofNullable(getCommand("premium")).ifPresent(c -> c.setExecutor(new PremiumCommand(this)));
Optional.ofNullable(getCommand("cracked")).ifPresent(c -> c.setExecutor(new CrackedCommand(this)));
if (pluginManager.isPluginEnabled("PlaceholderAPI")) {
premiumPlaceholder = new PremiumPlaceholder(this);
@@ -152,13 +147,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
}
}
private void registerCommands() {
//register commands using a unique name
Optional.ofNullable(getCommand("premium")).ifPresent(c -> c.setExecutor(new PremiumCommand(this)));
Optional.ofNullable(getCommand("cracked")).ifPresent(c -> c.setExecutor(new CrackedCommand(this)));
Optional.ofNullable(getCommand("fldelete")).ifPresent(c -> c.setExecutor(new DeleteCommand(this)));
}
private boolean initializeFloodgate() {
if (getServer().getPluginManager().getPlugin("Geyser-Spigot") != null) {
geyserService = new GeyserService(GeyserImpl.getInstance(), core);
@@ -240,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

View File

@@ -1,63 +0,0 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 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;
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -74,13 +74,11 @@ public class PremiumPlaceholder extends PlaceholderExpansion {
@Override
public @NotNull String getAuthor() {
//noinspection deprecation
return String.join(", ", plugin.getDescription().getAuthors());
}
@Override
public @NotNull String getVersion() {
//noinspection deprecation
return plugin.getDescription().getVersion();
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -30,7 +30,6 @@ import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPremiumToggleEv
import com.github.games647.fastlogin.core.storage.StoredProfile;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason;
@@ -58,31 +57,21 @@ public class CrackedCommand extends ToggleCommand {
return;
}
Player player = (Player) sender;
if (forwardCrackedCommand(sender, sender.getName())) {
return;
}
// todo: load async if
StoredProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName());
if (profile.isOnlinemodePreferred()) {
if (profile.isPremium()) {
plugin.getCore().sendLocaleMessage("remove-premium", sender);
profile.setOnlinemodePreferred(false);
profile.setPremium(false);
profile.setId(null);
plugin.getScheduler().runAsync(() -> {
plugin.getCore().getStorage().save(profile);
plugin.getServer().getPluginManager().callEvent(
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_OTHER)
);
plugin.getScheduler().getSyncExecutor().execute(() -> {
if (plugin.getCore().getConfig().getBoolean("kick-toggle", true)) {
player.kickPlayer(plugin.getCore().getMessage("remove-premium"));
} else {
plugin.getCore().sendLocaleMessage("add-premium", sender);
}
});
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
});
} else {
plugin.getCore().sendLocaleMessage("not-premium", sender);
@@ -106,16 +95,16 @@ public class CrackedCommand extends ToggleCommand {
}
//existing player is already cracked
if (profile.isExistingPlayer() && !profile.isOnlinemodePreferred()) {
if (profile.isSaved() && !profile.isPremium()) {
plugin.getCore().sendLocaleMessage("not-premium-other", sender);
} else {
plugin.getCore().sendLocaleMessage("remove-premium", sender);
profile.setOnlinemodePreferred(false);
profile.setPremium(false);
plugin.getScheduler().runAsync(() -> {
plugin.getCore().getStorage().save(profile);
plugin.getServer().getPluginManager().callEvent(
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_OTHER));
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
});
}
}

View File

@@ -1,94 +0,0 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 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.command;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
public class DeleteCommand implements TabExecutor {
private final FastLoginBukkit plugin;
public DeleteCommand(FastLoginBukkit plugin) {
this.plugin = plugin;
}
/**
* Handles the command to delete profiles.
*/
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission(command.getPermission())) {
plugin.getCore().sendLocaleMessage("no-permission", sender);
return true;
}
if (plugin.getBungeeManager().isEnabled()) {
sender.sendMessage("Error: Cannot delete profile entries when using BungeeCord!");
return false;
}
if (args.length < 1) {
sender.sendMessage("Error: Must supply username to delete!");
return false;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getCore().getStorage().deleteProfile(args[0]);
if (!(sender instanceof ConsoleCommandSender)) {
Bukkit.getScheduler().runTask(plugin, () -> {
if (count == 0) {
sender.sendMessage("Error: No profile entries found!");
} else {
sender.sendMessage("Deleted " + count + " matching profile entries");
}
});
}
});
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
List<String> list = new ArrayList<>();
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getName().toLowerCase().startsWith(args[0])) {
list.add(p.getName());
}
}
return null;
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -68,8 +68,7 @@ public class PremiumCommand extends ToggleCommand {
return;
}
Player player = (Player) sender;
UUID id = player.getUniqueId();
UUID id = ((Player) sender).getUniqueId();
if (plugin.getConfig().getBoolean("premium-warning") && !plugin.getCore().getPendingConfirms().contains(id)) {
sender.sendMessage(plugin.getCore().getMessage("premium-warning"));
plugin.getCore().getPendingConfirms().add(id);
@@ -79,25 +78,18 @@ public class PremiumCommand extends ToggleCommand {
plugin.getCore().getPendingConfirms().remove(id);
//todo: load async
StoredProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName());
if (profile.isOnlinemodePreferred()) {
if (profile.isPremium()) {
plugin.getCore().sendLocaleMessage("already-exists", sender);
} else {
//todo: resolve uuid
profile.setOnlinemodePreferred(true);
profile.setPremium(true);
plugin.getScheduler().runAsync(() -> {
plugin.getCore().getStorage().save(profile);
plugin.getServer().getPluginManager().callEvent(
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_SELF)
);
plugin.getScheduler().getSyncExecutor().execute(() -> {
if (plugin.getCore().getConfig().getBoolean("kick-toggle", true)) {
player.kickPlayer(plugin.getCore().getMessage("remove-premium"));
} else {
plugin.getCore().sendLocaleMessage("add-premium", sender);
}
});
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_SELF));
});
plugin.getCore().sendLocaleMessage("add-premium", sender);
}
}
@@ -117,16 +109,15 @@ public class PremiumCommand extends ToggleCommand {
return;
}
if (profile.isOnlinemodePreferred()) {
if (profile.isPremium()) {
plugin.getCore().sendLocaleMessage("already-exists-other", sender);
} else {
//todo: resolve uuid
profile.setOnlinemodePreferred(true);
profile.setPremium(true);
plugin.getScheduler().runAsync(() -> {
plugin.getCore().getStorage().save(profile);
plugin.getServer().getPluginManager().callEvent(
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_OTHER)
);
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
});
plugin.getCore().sendLocaleMessage("add-premium-other", sender);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -27,7 +27,6 @@ package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
@@ -35,15 +34,11 @@ import org.jetbrains.annotations.NotNull;
public class BukkitFastLoginPremiumToggleEvent extends Event implements FastLoginPremiumToggleEvent {
private static final HandlerList HANDLERS = new HandlerList();
private final CommandSender invoker;
private final StoredProfile profile;
private final PremiumToggleReason reason;
public BukkitFastLoginPremiumToggleEvent(CommandSender invoker, StoredProfile profile, PremiumToggleReason reason) {
public BukkitFastLoginPremiumToggleEvent(StoredProfile profile, PremiumToggleReason reason) {
super(true);
this.invoker = invoker;
this.profile = profile;
this.reason = reason;
}
@@ -53,13 +48,6 @@ public class BukkitFastLoginPremiumToggleEvent extends Event implements FastLogi
return profile;
}
/**
* @return who triggered this change. This could be a Player for itself or others (Admin) or the console.
*/
public CommandSender getInvoker() {
return invoker;
}
@Override
public PremiumToggleReason getReason() {
return reason;

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -45,9 +45,9 @@ import java.lang.reflect.Field;
* <p>
* Project page:
* <p>
* <a href="https://dev.bukkit.org/bukkit-plugins/authme-reloaded/">Bukkit</a>
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/authme-reloaded/">...</a>
* <p>
* <a href="https://www.spigotmc.org/resources/authme-reloaded.6269/">Spigot</a>
* Spigot: <a href="https://www.spigotmc.org/resources/authme-reloaded.6269/">...</a>
*/
public class AuthMeHook implements AuthPlugin<Player>, Listener {
@@ -76,7 +76,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
Player player = restoreSessionEvent.getPlayer();
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
if (session != null && session.isVerifiedPremium()) {
if (session != null && session.isVerified()) {
restoreSessionEvent.setCancelled(true);
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -46,7 +46,7 @@ import java.util.concurrent.Future;
* <p>
* Project page:
* <p>
* <a href="https://dev.bukkit.org/server-mods/crazylogin/">Bukkit</a>
* Bukkit: <a href="https://dev.bukkit.org/server-mods/crazylogin/">...</a>
*/
public class CrazyLoginHook implements AuthPlugin<Player> {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -39,9 +39,9 @@ import org.bukkit.entity.Player;
* <p>
* Project page:
* <p>
* <a href="https://dev.bukkit.org/bukkit-plugins/loginsecurity/">Bukkit</a>
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/loginsecurity/">...</a>
* <p>
* <a href="https://www.spigotmc.org/resources/loginsecurity.19362/">Spigot</a>
* Spigot: <a href="https://www.spigotmc.org/resources/loginsecurity.19362/">...</a>
*/
public class LoginSecurityHook implements AuthPlugin<Player> {

View File

@@ -1,68 +0,0 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 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.hook;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.rabbitcomapny.api.Identifier;
import com.rabbitcomapny.api.LoginResult;
import com.rabbitcomapny.api.PasskyAPI;
import com.rabbitcomapny.api.RegisterResult;
import org.bukkit.entity.Player;
public class PasskyHook implements AuthPlugin<Player> {
private final FastLoginBukkit plugin;
public PasskyHook(FastLoginBukkit plugin) {
this.plugin = plugin;
}
@Override
public boolean forceLogin(Player player) {
LoginResult result = PasskyAPI.forceLogin(new Identifier(player), true);
if (!result.success) {
plugin.getLog().error("Failed to force login {} via Passky: {}", player.getName(), result.status);
}
return result.success;
}
@Override
public boolean forceRegister(Player player, String password) {
RegisterResult result = PasskyAPI.forceRegister(new Identifier(player), password, true);
if (!result.success) {
plugin.getLog().error("Failed to register {} via Passky: {}", player.getName(), result.status);
}
return result.success;
}
@Override
public boolean isRegistered(String playerName) {
return PasskyAPI.isRegistered(new Identifier(playerName));
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -38,9 +38,9 @@ import java.util.concurrent.Future;
/**
* Project page:
* <p>
* <a href="https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/">Bukkit</a>
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/">...</a>
* <p>
* <a href="https://www.spigotmc.org/resources/ultraauth.17044/">Spigot</a>
* Spigot: <a href="https://www.spigotmc.org/resources/ultraauth.17044/">...</a>
*/
public class UltraAuthHook implements AuthPlugin<Player> {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -40,7 +40,7 @@ import java.util.concurrent.Future;
* <p>
* Project page:
* <p>
* <a href="https://dev.bukkit.org/bukkit-plugins/xauth/">Bukkit</a>
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/xauth/">...</a>
*/
public class XAuthHook implements AuthPlugin<Player> {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -123,7 +123,7 @@ public class BungeeListener implements PluginMessageListener {
}
private void startLoginTaskIfReady(Player player, BukkitLoginSession session) {
session.setVerifiedPremium(true);
session.setVerified(true);
plugin.putSession(player.spigot().getRawAddress(), session);
// only start a new login task if the join event fired earlier. This event then didn't

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -90,7 +90,6 @@ public class ConnectionListener implements Listener {
if (floodgatePlayer != null) {
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer);
Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
plugin.getBungeeManager().markJoinEventFired(player);
return;
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -31,6 +31,7 @@ import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.io.Resources;
import com.google.common.primitives.Longs;
import lombok.val;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -40,7 +41,6 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
@@ -53,7 +53,6 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Arrays;
@@ -71,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;
@@ -199,9 +198,9 @@ final class EncryptionUtil {
private static PublicKey loadMojangSessionKey()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
URL keyUrl = FastLoginBukkit.class.getClassLoader().getResource("yggdrasil_session_pubkey.der");
byte[] keyData = Resources.toByteArray(keyUrl);
KeySpec keySpec = new X509EncodedKeySpec(keyData);
val keyUrl = FastLoginBukkit.class.getClassLoader().getResource("yggdrasil_session_pubkey.der");
val keyData = Resources.toByteArray(keyUrl);
val keySpec = new X509EncodedKeySpec(keyData);
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -97,7 +97,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
}
String ip = player.getAddress().getAddress().getHostAddress();
core.addLoginAttempt(ip, username);
core.getPendingLogin().put(ip + username, new Object());
byte[] verify = source.getVerifyToken();
ClientPublicKey clientKey = source.getClientKey();

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -30,16 +30,15 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.netty.channel.NettyChannelInjector;
import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.Converters;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
@@ -49,9 +48,9 @@ import com.mojang.datafixers.util.Either;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.util.AttributeKey;
import lombok.val;
import org.bukkit.entity.Player;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.jetbrains.annotations.NotNull;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
@@ -74,6 +73,7 @@ import static com.comphenix.protocol.PacketType.Login.Client.START;
public class ProtocolLibListener extends PacketAdapter {
private final FastLoginBukkit plugin;
private final PlayerInjectionHandler handler;
//just create a new once on plugin enable. This used for verify token generation
private final SecureRandom random = new SecureRandom();
@@ -92,6 +92,7 @@ public class ProtocolLibListener extends PacketAdapter {
this.plugin = plugin;
this.antiBotService = antiBotService;
this.verifyClientKeys = verifyClientKeys;
this.handler = getHandler();
}
public static void register(FastLoginBukkit plugin, AntiBotService antiBotService, boolean verifyClientKeys) {
@@ -111,66 +112,45 @@ public class ProtocolLibListener extends PacketAdapter {
return;
}
plugin.getLog().info("New packet {} from {}", packetEvent.getPacketType(), packetEvent.getPlayer());
Player sender = packetEvent.getPlayer();
PacketType packetType = getOverriddenType(packetEvent.getPacketType());
PacketType packetType = packetEvent.getPacketType();
if (packetType == START) {
plugin.getLog().info("New incoming packet {} from {}", packetType, sender.getName());
try {
if (packetType == START) {
if (plugin.getFloodgateService() != null) {
boolean success = processFloodgateTasks(packetEvent);
if (!success) {
// don't continue execution if the player was kicked by Floodgate
return;
}
if (plugin.getFloodgateService() != null) {
boolean success = processFloodgateTasks(packetEvent);
// don't continue execution if the player was kicked by Floodgate
if (!success) {
return;
}
PacketContainer packet = packetEvent.getPacket();
InetSocketAddress address = sender.getAddress();
String username = getUsername(packet);
Action action = antiBotService.onIncomingConnection(address, username);
switch (action) {
case Ignore:
// just ignore
return;
case Block:
String message = plugin.getCore().getMessage("kick-antibot");
sender.kickPlayer(message);
break;
case Continue:
default:
//player.getName() won't work at this state
onLoginStart(packetEvent, sender, username);
break;
}
} else if (packetType == ENCRYPTION_BEGIN) {
onEncryptionBegin(packetEvent, sender);
} else {
plugin.getLog().warn("Unknown packet type received {}", packetType);
}
} catch (FieldAccessException fieldAccessEx) {
plugin.getLog().error("Failed to parse packet {}", packetEvent.getPacketType(), fieldAccessEx);
PacketContainer packet = packetEvent.getPacket();
InetSocketAddress address = sender.getAddress();
String username = getUsername(packet);
Action action = antiBotService.onIncomingConnection(address, username);
switch (action) {
case Ignore:
// just ignore
return;
case Block:
String message = plugin.getCore().getMessage("kick-antibot");
sender.kickPlayer(message);
break;
case Continue:
default:
//player.getName() won't work at this state
onLoginStart(packetEvent, sender, username);
break;
}
} else {
onEncryptionBegin(packetEvent, sender);
}
}
private @NotNull PacketType getOverriddenType(PacketType packetType) {
if (packetType.isDynamic()) {
String vanillaName = packetType.getPacketClass().getName();
plugin.getLog().info("Overriding packet type for unregistered packet type to fix ProtocolLib bug");
if (vanillaName.endsWith("ServerboundHelloPacket")) {
return START;
}
if (vanillaName.endsWith("ServerboundKeyPacket")) {
return ENCRYPTION_BEGIN;
}
}
return packetType;
}
private void onEncryptionBegin(PacketEvent packetEvent, Player sender) {
byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0);
@@ -197,7 +177,7 @@ public class ProtocolLibListener extends PacketAdapter {
ClientPublicKey clientPublicKey, byte[] expectedToken) {
try {
if (new MinecraftVersion(1, 19, 0).atOrAbove()
&& !new MinecraftVersion(1, 19, 3).atOrAbove()) {
&& !(new MinecraftVersion(1, 19, 3).atOrAbove())) {
Either<byte[], ?> either = packet.getSpecificModifier(Either.class).read(0);
if (clientPublicKey == null) {
Optional<byte[]> left = either.left();
@@ -242,12 +222,11 @@ public class ProtocolLibListener extends PacketAdapter {
PacketContainer packet = packetEvent.getPacket();
Optional<ClientPublicKey> clientKey;
if (new MinecraftVersion(1, 19, 3).atOrAbove()) {
// public key is sent separate
// public key sent separate
clientKey = Optional.empty();
} else {
Optional<Optional<WrappedProfileKeyData>> profileKey = packet.getOptionals(
BukkitConverters.getWrappedPublicKeyDataConverter()
).optionRead(0);
val profileKey = packet.getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter())
.optionRead(0);
clientKey = profileKey.flatMap(Function.identity()).flatMap(data -> {
Instant expires = data.getExpireTime();
@@ -268,6 +247,7 @@ public class ProtocolLibListener extends PacketAdapter {
}
}
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay();
@@ -295,17 +275,16 @@ public class ProtocolLibListener extends PacketAdapter {
return profile.getName();
}
private FloodgatePlayer getFloodgatePlayer(Player player) {
Channel channel = getChannel(player);
AttributeKey<FloodgatePlayer> floodgateAttribute = AttributeKey.valueOf("floodgate-player");
return channel.attr(floodgateAttribute).get();
private static PlayerInjectionHandler getHandler() {
PacketFilterManager manager = (PacketFilterManager) ProtocolLibrary.getProtocolManager();
FieldAccessor accessor = Accessors.getFieldAccessor(manager.getClass(), PlayerInjectionHandler.class, true);
return (PlayerInjectionHandler) accessor.get(manager);
}
private static Channel getChannel(Player player) {
NettyChannelInjector injector = (NettyChannelInjector) Accessors.getMethodAccessorOrNull(
TemporaryPlayerFactory.class, "getInjectorFromPlayer", Player.class
).invoke(null, player);
return FuzzyReflection.getFieldValue(injector, Channel.class, true);
private FloodgatePlayer getFloodgatePlayer(Player player) {
Channel channel = handler.getChannel(player);
AttributeKey<FloodgatePlayer> floodgateAttribute = AttributeKey.valueOf("floodgate-player");
return channel.attr(floodgateAttribute).get();
}
/**
@@ -324,7 +303,7 @@ public class ProtocolLibListener extends PacketAdapter {
}
// kick the player, if necessary
Channel channel = getChannel(packetEvent.getPlayer());
Channel channel = handler.getChannel(packetEvent.getPlayer());
AttributeKey<String> kickMessageAttribute = AttributeKey.valueOf("floodgate-kick-message");
String kickMessage = channel.attr(kickMessageAttribute).get();
if (kickMessage != null) {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -51,6 +51,7 @@ class ProtocolLibLoginSource implements LoginSource {
private final ClientPublicKey clientKey;
private final PublicKey publicKey;
private final String serverId = "";
private byte[] verifyToken;
ProtocolLibLoginSource(Player player, Random random, PublicKey serverPublicKey, ClientPublicKey clientKey) {
@@ -71,7 +72,7 @@ class ProtocolLibLoginSource implements LoginSource {
*/
PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN);
newPacket.getStrings().write(0, "");
newPacket.getStrings().write(0, serverId);
StructureModifier<PublicKey> keyModifier = newPacket.getSpecificModifier(PublicKey.class);
int verifyField = 0;
if (keyModifier.getFields().isEmpty()) {
@@ -83,8 +84,6 @@ class ProtocolLibLoginSource implements LoginSource {
}
newPacket.getByteArrays().write(verifyField, verifyToken);
// shouldAuthenticate, but why does this field even exist?
newPacket.getBooleans().writeSafely(0, true);
//serverId is an empty string
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket);
@@ -116,6 +115,10 @@ class ProtocolLibLoginSource implements LoginSource {
return clientKey;
}
public String getServerId() {
return serverId;
}
public byte[] getVerifyToken() {
return verifyToken.clone();
}
@@ -125,6 +128,7 @@ class ProtocolLibLoginSource implements LoginSource {
return this.getClass().getSimpleName() + '{'
+ "player=" + player
+ ", random=" + random
+ ", serverId='" + serverId + '\''
+ ", verifyToken=" + Arrays.toString(verifyToken)
+ '}';
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -28,7 +28,6 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.netty.channel.NettyChannelInjector;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.EquivalentConverter;
@@ -39,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;
@@ -48,8 +46,8 @@ 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;
import javax.crypto.Cipher;
@@ -72,13 +70,13 @@ import static com.comphenix.protocol.PacketType.Login.Server.DISCONNECT;
public class VerifyResponseTask implements Runnable {
private static final String ENCRYPTION_CLASS_NAME = "MinecraftEncryption";
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.";
private static final Class<?> ENCRYPTION_CLASS;
static {
ENCRYPTION_CLASS = MinecraftReflection.getMinecraftClass(
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
);
}
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
@@ -91,8 +89,6 @@ public class VerifyResponseTask implements Runnable {
private final byte[] sharedSecret;
private static Method encryptMethod;
private static Method encryptKeyMethod;
private static Method cipherMethod;
public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent,
@@ -153,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
);
} 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);
@@ -195,10 +174,10 @@ public class VerifyResponseTask implements Runnable {
session.setVerifiedUsername(realUsername);
session.setUuid(verification.getId());
session.setVerifiedPremium(true);
session.setVerified(true);
setPremiumUUID(session.getUuid());
receiveFakeStartPacket(realUsername, session.getClientPublicKey(), session.getUuid());
receiveFakeStartPacket(realUsername, session.getClientPublicKey());
}
private void setPremiumUUID(UUID premiumUUID) {
@@ -218,37 +197,35 @@ public class VerifyResponseTask implements Runnable {
//try to get the networkManager from ProtocolLib
private Object getNetworkManager() throws ClassNotFoundException {
NettyChannelInjector injectorContainer = (NettyChannelInjector) Accessors.getMethodAccessorOrNull(
TemporaryPlayerFactory.class, "getInjectorFromPlayer", Player.class
).invoke(null, player);
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
FieldAccessor accessor = Accessors.getFieldAccessorOrNull(
NettyChannelInjector.class, "networkManager", Object.class
);
return accessor.get(injectorContainer);
// ChannelInjector
Class<?> injectorClass = Class.forName("com.comphenix.protocol.injector.netty.Injector");
Object rawInjector = FuzzyReflection.getFieldValue(injectorContainer, injectorClass, true);
Class<?> rawInjectorClass = rawInjector.getClass();
FieldAccessor accessor = Accessors.getFieldAccessorOrNull(rawInjectorClass, "networkManager", Object.class);
return accessor.get(rawInjector);
}
private boolean enableEncryption(SecretKey loginKey) throws IllegalArgumentException {
plugin.getLog().info("Enabling onlinemode encryption for {}", player.getAddress());
// Initialize method reflections
if (encryptKeyMethod == null || encryptMethod == null) {
if (encryptMethod == null) {
Class<?> networkManagerClass = MinecraftReflection.getNetworkManagerClass();
try {
// Try to get the old (pre MC 1.16.4) encryption method
encryptKeyMethod = FuzzyReflection.fromClass(networkManagerClass)
.getMethodByParameters("a", SecretKey.class);
encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
.getMethodByParameters("a", SecretKey.class);
} catch (IllegalArgumentException exception) {
// Get the new encryption method
encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
.getMethodByParameters("a", Cipher.class, Cipher.class);
Class<?> encryptionClass = MinecraftReflection.getMinecraftClass(
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
);
.getMethodByParameters("a", Cipher.class, Cipher.class);
// Get the needed Cipher helper method (used to generate ciphers from login key)
cipherMethod = FuzzyReflection.fromClass(encryptionClass)
.getMethodByParameters("a", int.class, Key.class);
cipherMethod = FuzzyReflection.fromClass(ENCRYPTION_CLASS)
.getMethodByParameters("a", int.class, Key.class);
}
}
@@ -256,9 +233,9 @@ public class VerifyResponseTask implements Runnable {
Object networkManager = this.getNetworkManager();
// If cipherMethod is null - use old encryption (pre MC 1.16.4), otherwise use the new cipher one
if (encryptKeyMethod != null) {
if (cipherMethod == null) {
// Encrypt/decrypt packet flow, this behaviour is expected by the client
encryptKeyMethod.invoke(networkManager, loginKey);
encryptMethod.invoke(networkManager, loginKey);
} else {
// Create ciphers from login key
Object decryptionCipher = cipherMethod.invoke(null, Cipher.DECRYPT_MODE, loginKey);
@@ -291,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();
Optional<WrappedProfileKeyData> wrappedKey = Optional.ofNullable(clientKey).map(key ->
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
val wrappedKey = Optional.ofNullable(clientKey).map(key ->
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
);
startPacket.getOptionals(converter).write(0, wrappedKey);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -25,38 +25,20 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib.packet;
import lombok.Value;
import lombok.experimental.Accessors;
import java.security.PublicKey;
import java.time.Instant;
import java.util.Base64;
import java.util.StringJoiner;
@Accessors(fluent = true)
@Value(staticConstructor = "of")
public class ClientPublicKey {
private final Instant expiry;
private final PublicKey key;
private final byte[] signature;
public Instant expiry() {
return expiry;
}
public PublicKey key() {
return key;
}
public byte[] signature() {
return signature;
}
public ClientPublicKey(Instant expiry, PublicKey key, byte[] signature) {
this.expiry = expiry;
this.key = key;
this.signature = signature;
}
public static ClientPublicKey of(Instant expiry, PublicKey key, byte[] signature) {
return new ClientPublicKey(expiry, key, signature);
}
Instant expiry;
PublicKey key;
byte[] signature;
public boolean isExpired(Instant verifyTimestamp) {
return !verifyTimestamp.isBefore(expiry);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -101,7 +101,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
BukkitLoginSession session = plugin.getSession(address);
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
session.setVerifiedPremium(true);
session.setVerified(true);
if (!plugin.getConfig().getBoolean("premiumUuid")) {
String username = Optional.ofNullable(profileCompleteEvent.getForcedName())
@@ -125,7 +125,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
source.enableOnlinemode();
String ip = source.getAddress().getAddress().getHostAddress();
plugin.getCore().addLoginAttempt(ip, username);
plugin.getCore().getPendingLogin().put(ip + username, new Object());
BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile);
plugin.putSession(source.getAddress(), playerSession);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -32,7 +32,6 @@ import com.github.games647.fastlogin.bukkit.hook.LogItHook;
import com.github.games647.fastlogin.bukkit.hook.LoginSecurityHook;
import com.github.games647.fastlogin.bukkit.hook.UltraAuthHook;
import com.github.games647.fastlogin.bukkit.hook.XAuthHook;
import com.github.games647.fastlogin.bukkit.hook.PasskyHook;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -95,7 +94,7 @@ public class DelayedAuthHook implements Runnable {
try {
List<Class<? extends AuthPlugin<Player>>> hooks = Arrays.asList(AuthMeHook.class,
CrazyLoginHook.class, LogItHook.class, LoginSecurityHook.class, UltraAuthHook.class,
XAuthHook.class, PasskyHook.class);
XAuthHook.class);
for (Class<? extends AuthPlugin<Player>> clazz : hooks) {
String pluginName = clazz.getSimpleName();

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -49,7 +49,7 @@ public class FloodgateAuthTask extends FloodgateManagement<Player, CommandSender
BukkitLoginSession session = new BukkitLoginSession(player.getName(), isRegistered, profile);
// enable auto login based on the value of 'autoLoginFloodgate' in config.yml
session.setVerifiedPremium(isAutoAuthAllowed(autoLoginFloodgate));
session.setVerified(isAutoAuthAllowed(autoLoginFloodgate));
// run login task
Runnable forceLoginTask = new ForceLoginTask(core.getPlugin().getCore(), player, session);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -103,6 +103,6 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
@Override
public boolean isOnlineMode() {
return session.isVerifiedPremium();
return session.isVerified();
}
}

View File

@@ -25,12 +25,12 @@ softdepend:
- floodgate
# Auth plugins
- AuthMe
- CrazyLogin
- LoginSecurity
- SodionAuth
- xAuth
- LogIt
- UltraAuth
- xAuth
- Passky
- CrazyLogin
commands:
${project.parent.name}:
@@ -45,11 +45,6 @@ commands:
usage: /<command> [player]
permission: ${project.artifactId}.command.cracked
fldelete:
description: 'Delete player profile data'
usage: /<command> [player]
permission: ${project.artifactId}.command.delete
permissions:
${project.artifactId}.command.premium:
description: 'Label themselves as premium'
@@ -68,7 +63,3 @@ permissions:
description: 'Label others as cracked'
children:
${project.artifactId}.command.cracked: true
${project.artifactId}.command.delete:
description: 'Delete other players profile data'
default: op

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -26,7 +26,7 @@
package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.core.CommonUtil;
import net.md_5.bungee.api.chat.BaseComponent;
import lombok.val;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.jupiter.api.Test;
@@ -37,14 +37,12 @@ class FastLoginBukkitTest {
@Test
void testRGB() {
String message = "&x00002a00002b&lText";
String msg = CommonUtil.translateColorCodes(message);
val message = "&x00002a00002b&lText";
val msg = CommonUtil.translateColorCodes(message);
assertEquals(msg, "§x00002a00002b§lText");
@SuppressWarnings("deprecation")
BaseComponent[] components = TextComponent.fromLegacyText(msg);
String expected = "{\"bold\":true,\"color\":\"#00a00b\",\"text\":\"Text\"}";
//noinspection deprecation
val components = TextComponent.fromLegacyText(msg);
val expected = "{\"bold\":true,\"color\":\"#00a00b\",\"text\":\"Text\"}";
assertEquals(ComponentSerializer.toString(components), expected);
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import lombok.val;
import java.io.IOException;
import java.util.Base64;
@@ -36,7 +37,7 @@ public class Base64Adapter extends TypeAdapter<byte[]> {
@Override
public void write(JsonWriter out, byte[] value) throws IOException {
String encoded = Base64.getEncoder().encodeToString(value);
val encoded = Base64.getEncoder().encodeToString(value);
out.value(encoded);
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -27,8 +27,8 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.github.games647.fastlogin.bukkit.listener.protocollib.SignatureTestData.SignatureData;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import lombok.val;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -51,7 +51,6 @@ import java.security.SignatureException;
import java.security.interfaces.RSAPublicKey;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@@ -61,7 +60,7 @@ class EncryptionUtilTest {
@Test
void testVerifyToken() {
Random random = ThreadLocalRandom.current();
val random = ThreadLocalRandom.current();
byte[] token = EncryptionUtil.generateVerifyToken(random);
assertAll(
@@ -89,10 +88,10 @@ class EncryptionUtilTest {
@Test
void testExpiredClientKey() throws Exception {
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
// Client expires at the exact second mentioned, so use it for verification
Instant expiredTimestamp = clientKey.expiry();
val expiredTimestamp = clientKey.expiry();
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp, null));
}
@@ -106,7 +105,7 @@ class EncryptionUtilTest {
"client_keys/invalid_wrong_signature.json"
})
void testInvalidClientKey(String clientKeySource) throws Exception {
ClientPublicKey clientKey = ResourceLoader.loadClientKey(clientKeySource);
val clientKey = ResourceLoader.loadClientKey(clientKeySource);
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp, null));
@@ -114,34 +113,34 @@ class EncryptionUtilTest {
@Test
void testValidClientKey() throws Exception {
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, null));
}
@Test
void testValid191ClientKey() throws Exception {
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
UUID ownerPremiumId = UUID.fromString("0aaa2c13-922a-411b-b655-9b8c08404695");
val ownerPremiumId = UUID.fromString("0aaa2c13-922a-411b-b655-9b8c08404695");
assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, ownerPremiumId));
}
@Test
void testIncorrect191ClientOwner() throws Exception {
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
UUID ownerPremiumId = UUID.fromString("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6");
val ownerPremiumId = UUID.fromString("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6");
assertFalse(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, ownerPremiumId));
}
@Test
void testDecryptSharedSecret() throws Exception {
KeyPair serverPair = EncryptionUtil.generateKeyPair();
PublicKey serverPK = serverPair.getPublic();
val serverPK = serverPair.getPublic();
SecretKey secretKey = generateSharedKey();
byte[] encryptedSecret = encrypt(serverPK, secretKey.getEncoded());
@@ -153,7 +152,7 @@ class EncryptionUtilTest {
private static byte[] encrypt(PublicKey receiverKey, byte... message)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
Cipher encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
val encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
encryptCipher.init(Cipher.ENCRYPT_MODE, receiverKey);
return encryptCipher.doFinal(message);
}
@@ -169,9 +168,9 @@ class EncryptionUtilTest {
@Test
void testServerIdHash() throws Exception {
String serverId = "";
SecretKeySpec sharedSecret = generateSharedKey();
PublicKey serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
val serverId = "";
val sharedSecret = generateSharedKey();
val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
assertEquals(EncryptionUtil.getServerIdHashString(serverId, sharedSecret, serverPK), sessionHash);
@@ -186,7 +185,7 @@ class EncryptionUtilTest {
// sha1.update(server's encoded public key from Encryption Request)
// hash := sha1.hexdigest() # String of hex characters
@SuppressWarnings("deprecation")
Hasher hasher = Hashing.sha1().newHasher();
val hasher = Hashing.sha1().newHasher();
hasher.putString(serverId, StandardCharsets.US_ASCII);
hasher.putBytes(sharedSecret.getEncoded());
hasher.putBytes(serverPK.getEncoded());
@@ -199,9 +198,9 @@ class EncryptionUtilTest {
@Test
void testServerIdHashWrongSecret() throws Exception {
String serverId = "";
SecretKeySpec sharedSecret = generateSharedKey();
PublicKey serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
val serverId = "";
val sharedSecret = generateSharedKey();
val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
assertNotEquals(EncryptionUtil.getServerIdHashString("", generateSharedKey(), serverPK), sessionHash);
@@ -209,12 +208,12 @@ class EncryptionUtilTest {
@Test
void testServerIdHashWrongServerKey() {
String serverId = "";
SecretKeySpec sharedSecret = generateSharedKey();
PublicKey serverPK = EncryptionUtil.generateKeyPair().getPublic();
val serverId = "";
val sharedSecret = generateSharedKey();
val serverPK = EncryptionUtil.generateKeyPair().getPublic();
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
PublicKey wrongPK = EncryptionUtil.generateKeyPair().getPublic();
val wrongPK = EncryptionUtil.generateKeyPair().getPublic();
assertNotEquals(EncryptionUtil.getServerIdHashString("", sharedSecret, wrongPK), sessionHash);
}
@@ -258,8 +257,8 @@ class EncryptionUtilTest {
@Test
void testNonce() throws Exception {
byte[] expected = {1, 2, 3, 4};
KeyPair serverKey = EncryptionUtil.generateKeyPair();
byte[] encryptedNonce = encrypt(serverKey.getPublic(), expected);
val serverKey = EncryptionUtil.generateKeyPair();
val encryptedNonce = encrypt(serverKey.getPublic(), expected);
assertTrue(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce));
}
@@ -267,19 +266,19 @@ class EncryptionUtilTest {
@Test
void testNonceIncorrect() throws Exception {
byte[] expected = {1, 2, 3, 4};
KeyPair serverKey = EncryptionUtil.generateKeyPair();
val serverKey = EncryptionUtil.generateKeyPair();
// flipped first character
byte[] encryptedNonce = encrypt(serverKey.getPublic(), new byte[]{0, 2, 3, 4});
val encryptedNonce = encrypt(serverKey.getPublic(), new byte[]{0, 2, 3, 4});
assertFalse(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce));
}
@Test
void testNonceFailedDecryption() throws Exception {
byte[] expected = {1, 2, 3, 4};
KeyPair serverKey = EncryptionUtil.generateKeyPair();
val serverKey = EncryptionUtil.generateKeyPair();
// generate a new keypair that is different
byte[] encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
val encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
assertThrows(GeneralSecurityException.class,
() -> EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce)
@@ -289,7 +288,7 @@ class EncryptionUtilTest {
@Test
void testNonceIncorrectEmpty() {
byte[] expected = {1, 2, 3, 4};
KeyPair serverKey = EncryptionUtil.generateKeyPair();
val serverKey = EncryptionUtil.generateKeyPair();
byte[] encryptedNonce = {};
assertThrows(GeneralSecurityException.class,

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -28,16 +28,16 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.annotations.JsonAdapter;
import lombok.val;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class SignatureTestData {
public static SignatureTestData fromResource(String resourceName) throws IOException {
URL keyUrl = Resources.getResource(resourceName);
String encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
val keyUrl = Resources.getResource(resourceName);
val encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
return new Gson().fromJson(encodedSignature, SignatureTestData.class);
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -26,6 +26,7 @@
package com.github.games647.fastlogin.bukkit.task;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import lombok.val;
import org.bukkit.entity.Player;
import org.junit.jupiter.api.Test;
@@ -35,7 +36,7 @@ class DelayedAuthHookTest {
@Test
void createNewReflectiveInstance() throws ReflectiveOperationException {
DelayedAuthHook authHook = new DelayedAuthHook(null);
val authHook = new DelayedAuthHook(null);
assertNotNull(authHook.newInstance(DummyHook.class));
}

View File

@@ -4,7 +4,7 @@
The MIT License (MIT)
Copyright (c) 2015-2024 games647 and contributors
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
@@ -40,10 +40,6 @@
<artifactId>fastlogin.bungee</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<!--Represents the main plugin-->
<name>FastLoginBungee</name>
@@ -51,12 +47,20 @@
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<version>3.4.1</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>false</shadedArtifactAttached>
<artifactSet>
<excludes>
<!--Those classes are already present in BungeeCord version-->
<exclude>net.md-5:bungeecord-config</exclude>
<exclude>com.google.code.gson:gson</exclude>
<exclude>com.google.guava:guava</exclude>
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
@@ -78,7 +82,6 @@
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
<exclude>**/module-info</exclude>
<exclude>**/module-info.class</exclude>
</excludes>
</filter>
@@ -117,33 +120,13 @@
<groupId>${project.groupId}</groupId>
<artifactId>fastlogin.core</artifactId>
<version>${project.version}</version>
<!--Those classes are already present in BungeeCord version-->
<exclusions>
<exclusion>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<!-- Exclude snakeyaml, because it is included in BungeeCord with the correct version -->
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--BungeeCord with also the part outside the API-->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<version>1.19-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<!-- Use our own newer api version -->
<exclusions>
@@ -152,14 +135,13 @@
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.mysql</groupId>
<groupId>mysql</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId>
</exclusion>
<exclusion>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-query</artifactId>
@@ -168,11 +150,6 @@
<groupId>net.md-5</groupId>
<artifactId>bungeecord-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>*</artifactId>
@@ -181,10 +158,6 @@
<groupId>org.apache.maven.resolver</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -54,15 +54,9 @@ public class BungeeLoginSource implements LoginSource {
preLoginEvent.setCancelled(true);
if (message == null) {
preLoginEvent.setReason(
TextComponent.fromArray(
new ComponentBuilder("Kicked").color(ChatColor.WHITE).create()
));
preLoginEvent.setCancelReason(new ComponentBuilder("Kicked").color(ChatColor.WHITE).create());
} else {
preLoginEvent.setReason(
TextComponent.fromArray(
TextComponent.fromLegacyText(message)
));
preLoginEvent.setCancelReason(TextComponent.fromLegacyText(message));
}
}
@@ -78,7 +72,7 @@ public class BungeeLoginSource implements LoginSource {
@Override
public String toString() {
return this.getClass().getSimpleName() + '{'
+ "connection=" + connection
+ '}';
+ "connection=" + connection
+ '}';
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.bungee.hook.BungeeAuthHook;
import com.github.games647.fastlogin.bungee.listener.ConnectListener;
import com.github.games647.fastlogin.bungee.listener.PluginMessageListener;
import com.github.games647.fastlogin.core.AsyncScheduler;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.bedrock.BedrockService;
@@ -37,7 +38,6 @@ import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.message.SuccessMessage;
import com.github.games647.fastlogin.core.scheduler.AsyncScheduler;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.google.common.collect.MapMaker;
@@ -98,7 +98,7 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
//events
PluginManager pluginManager = getProxy().getPluginManager();
Listener connectListener = new ConnectListener(this, core.getAntiBotService());
Listener connectListener = new ConnectListener(this, core.getAntiBot());
pluginManager.registerListener(this, connectListener);
pluginManager.registerListener(this, new PluginMessageListener(this));

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -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) {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -131,7 +131,7 @@ public class PluginMessageListener implements Listener {
loginSession.setRegistered(true);
if (!loginSession.isAlreadySaved()) {
playerProfile.setOnlinemodePreferred(true);
playerProfile.setPremium(true);
plugin.getCore().getStorage().save(playerProfile);
loginSession.setAlreadySaved(true);
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -81,7 +81,7 @@ public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSend
plugin.getSession().put(source.getConnection(), new BungeeLoginSession(username, registered, profile));
String ip = source.getAddress().getAddress().getHostAddress();
plugin.getCore().addLoginAttempt(ip, username);
plugin.getCore().getPendingLogin().put(ip + username, new Object());
}
@Override

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -64,34 +64,29 @@ public class AsyncToggleMessage implements Runnable {
private void turnOffPremium() {
StoredProfile playerProfile = core.getStorage().loadProfile(targetPlayer);
//existing player is already cracked
if (playerProfile.isExistingPlayer() && !playerProfile.isOnlinemodePreferred()) {
if (playerProfile.isSaved() && !playerProfile.isPremium()) {
sendMessage("not-premium");
return;
}
playerProfile.setOnlinemodePreferred(false);
playerProfile.setPremium(false);
playerProfile.setId(null);
core.getStorage().save(playerProfile);
PremiumToggleReason reason = (!isPlayerSender || !sender.getName().equalsIgnoreCase(playerProfile.getName()))
? PremiumToggleReason.COMMAND_OTHER : PremiumToggleReason.COMMAND_SELF;
core.getPlugin().getProxy().getPluginManager().callEvent(
new BungeeFastLoginPremiumToggleEvent(playerProfile, reason));
if (isPlayerSender && core.getConfig().getBoolean("kick-toggle", true)) {
sender.disconnect(TextComponent.fromLegacyText(core.getMessage("remove-premium")));
} else {
sendMessage("remove-premium");
}
sendMessage("remove-premium");
}
private void activatePremium() {
StoredProfile playerProfile = core.getStorage().loadProfile(targetPlayer);
if (playerProfile.isOnlinemodePreferred()) {
if (playerProfile.isPremium()) {
sendMessage("already-exists");
return;
}
playerProfile.setOnlinemodePreferred(true);
playerProfile.setPremium(true);
core.getStorage().save(playerProfile);
PremiumToggleReason reason = (!isPlayerSender || !sender.getName().equalsIgnoreCase(playerProfile.getName()))
? PremiumToggleReason.COMMAND_OTHER : PremiumToggleReason.COMMAND_SELF;

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -11,6 +11,8 @@ author: games647, https://github.com/games647/FastLogin/graphs/contributors
softDepends:
# BungeeCord auth plugins
- BungeeAuth
- BungeeCordAuthenticatorBungee
- SodionAuth
# Bedrock Player Bridge
- Geyser-BungeeCord
- floodgate

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -5,7 +5,7 @@
The MIT License (MIT)
Copyright (c) 2015-2024 games647 and contributors
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
@@ -29,6 +29,35 @@
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
https://docs.oracle.com/javase/specs/jls/se11/html/index.html
- the Sun Code Conventions at https://www.oracle.com/java/technologies/javase/codeconventions-contents.html
- the Javadoc guidelines at
https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html
- the JDK Api documentation https://docs.oracle.com/en/java/javase/11/
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
https://checkstyle.org (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
To suppress certain violations please review suppression filters.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!--
If you set the basedir property below, then all reported file
@@ -191,12 +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>

View File

@@ -4,7 +4,7 @@
The MIT License (MIT)
Copyright (c) 2015-2024 games647 and contributors
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
@@ -39,11 +39,6 @@
<artifactId>fastlogin.core</artifactId>
<packaging>jar</packaging>
<properties>
<!-- Still force Java 8 for the remaining project -->
<maven.compiler.release>8</maven.compiler.release>
</properties>
<name>FastLoginCore</name>
<repositories>
@@ -60,7 +55,7 @@
</repository>
<!-- Floodgate -->
<repository>
<id>opencollab</id>
<id>opencollab-snapshot</id>
<url>https://repo.opencollab.dev/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
@@ -68,56 +63,6 @@
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.github.games647.fastlogin.core</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jdk21</id>
<activation>
<jdk>[21,)</jdk>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>jdk21</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>21</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java21</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
<dependencies>
<!-- Libraries that we shade into the project -->
@@ -140,21 +85,14 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.17</version>
<version>2.0.7</version>
</dependency>
<!-- snakeyaml is present in Bungee, Spigot, so we could use this independent implementation -->
<!-- snakeyaml is present in Bungee, Spigot, Cauldron, so we could use this independent implementation -->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
<version>1.20-R0.2</version>
</dependency>
<!-- This is optional in BungeeCord-config, so we include it here manually -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.4</version>
<version>1.19-R0.1-SNAPSHOT</version>
</dependency>
<!--Floodgate for Xbox Live Authentication-->
@@ -203,10 +141,46 @@
<dependency>
<groupId>com.github.games647</groupId>
<artifactId>craftapi</artifactId>
<version>1.0-SNAPSHOT</version>
<version>0.6.2</version>
</dependency>
<!-- APIs we can use because they are available in all platforms (Spigot, Bungee, Velocity) -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<!-- Old version for velocity -->
<version>25.1-jre</version>
<!-- Exclude compile time dependencies not marked as such on upstream -->
<exclusions>
<exclusion>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</exclusion>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.j2objc</groupId>
<artifactId>j2objc-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
<!-- Database driver included in Spigot -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -23,22 +23,36 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.games647.fastlogin.core.scheduler;
package com.github.games647.fastlogin.core;
import org.slf4j.Logger;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractAsyncScheduler {
/**
* This limits the number of threads that are used at maximum. Thread creation can be very heavy for the CPU and
* context switching between threads too. However, we need many threads for blocking HTTP and database calls.
* Nevertheless, this number can be further limited, because the number of actually working database threads
* is limited by the size of our database pool. The goal is to separate concerns into processing and blocking only
* threads.
*/
public class AsyncScheduler {
protected final Logger logger;
protected final Executor processingPool;
protected final AtomicInteger currentlyRunning = new AtomicInteger();
private static final int MAX_CAPACITY = 1024;
public AbstractAsyncScheduler(Logger logger, Executor processingPool) {
//todo: single thread for delaying and scheduling tasks
private final Logger logger;
// 30 threads are still too many - the optimal solution is to separate into processing and blocking threads
// where processing threads could only be max number of cores while blocking threads could be minimized using
// non-blocking I/O and a single event executor
private final Executor processingPool;
private final AtomicInteger currentlyRunning = new AtomicInteger();
public AsyncScheduler(Logger logger, Executor processingPool) {
this.logger = logger;
this.processingPool = processingPool;
}
@@ -50,25 +64,7 @@ public abstract class AbstractAsyncScheduler {
});
}
public CompletableFuture<Void> runAsyncDelayed(Runnable task, Duration delay) {
return CompletableFuture.runAsync(() -> {
currentlyRunning.incrementAndGet();
try {
Thread.sleep(delay.toMillis());
task.run();
} catch (InterruptedException interruptedException) {
// restore interrupt flag
Thread.currentThread().interrupt();
} finally {
currentlyRunning.getAndDecrement();
}
}, processingPool).exceptionally(error -> {
logger.warn("Error occurred on thread pool", error);
return null;
});
}
protected void process(Runnable task) {
private void process(Runnable task) {
currentlyRunning.incrementAndGet();
try {
task.run();

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -32,8 +32,8 @@ import org.slf4j.jul.JDK14LoggerAdapter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public final class CommonUtil {
@@ -41,11 +41,11 @@ public final class CommonUtil {
private static final char COLOR_CHAR = '&';
private static final char TRANSLATED_CHAR = '§';
public static <K, V> ConcurrentMap<K, V> buildCache(Duration expireAfterWrite, int maxSize) {
public static <K, V> ConcurrentMap<K, V> buildCache(int expireAfterWrite, int maxSize) {
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
if (expireAfterWrite != null) {
builder.expireAfterWrite(expireAfterWrite);
if (expireAfterWrite > 0) {
builder.expireAfterWrite(expireAfterWrite, TimeUnit.MINUTES);
}
if (maxSize > 0) {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -27,9 +27,10 @@ package com.github.games647.fastlogin.core;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.craftapi.resolver.Options;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.util.Optional;
@@ -43,12 +44,38 @@ import java.util.Optional;
*/
public class ProxyAgnosticMojangResolver extends MojangResolver {
public ProxyAgnosticMojangResolver(Options options) {
super(options);
}
private static final String HOST = "sessionserver.mojang.com";
/**
* A formatting string containing a URL used to call the {@code hasJoined} method on mojang session servers.
* <p>
* Formatting parameters:
* 1. The username of the player in question
* 2. The serverId of this server
*/
public static final String ENDPOINT = "https://" + HOST + "/session/minecraft/hasJoined?username=%s&serverId=%s";
@Override
public Optional<Verification> hasJoined(String username, String serverHash, InetAddress hostIp)
throws IOException {
return super.hasJoined(username, serverHash, null);
String url = String.format(ENDPOINT, username, serverHash);
HttpURLConnection conn = this.getConnection(url);
int responseCode = conn.getResponseCode();
Verification verification = null;
// Mojang session servers send HTTP 204 (NO CONTENT) when the authentication seems invalid
// If that's not our case, the authentication is valid, and so we can parse the response.
if (responseCode != HttpURLConnection.HTTP_NO_CONTENT) {
verification = this.parseRequest(conn, this::parseVerification);
}
return Optional.ofNullable(verification);
}
// Functional implementation of InputStreamAction, used in hasJoined method in parseRequest call
protected Verification parseVerification(InputStream input) throws IOException {
return this.readJson(input, Verification.class);
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -107,7 +107,7 @@ public class TickingRateLimiter implements RateLimiter {
}
}
private static class TimeRecord implements Comparable<TimeRecord> {
private static class TimeRecord implements Comparable<Long> {
private final long firstMinuteRecord;
private final long expireTime;
@@ -131,9 +131,9 @@ public class TickingRateLimiter implements RateLimiter {
return firstMinuteRecord + expireTime <= now;
}
public int compareTo(long other) {
@Override
public int compareTo(Long other) {
if (other < firstMinuteRecord) {
// other is earlier
return -1;
}
@@ -143,10 +143,5 @@ public class TickingRateLimiter implements RateLimiter {
return 0;
}
@Override
public int compareTo(TimeRecord other) {
return compareTo(other.firstMinuteRecord);
}
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -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 player representation
* @return generated password
*/
String getRandomPassword(P player);
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -63,7 +63,7 @@ public class LoginActionMessage implements ChannelMessage {
@Override
public void readFrom(ByteArrayDataInput input) {
this.type = Type.values()[input.readByte()];
this.type = Type.values()[input.readInt()];
this.playerName = input.readUTF();
@@ -75,7 +75,7 @@ public class LoginActionMessage implements ChannelMessage {
@Override
public void writeTo(ByteArrayDataOutput output) {
output.writeByte(type.ordinal());
output.writeInt(type.ordinal());
//Data is sent through a random player. We have to tell the Bukkit version of this plugin the target
output.writeUTF(playerName);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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

View File

@@ -1,47 +0,0 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 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.scheduler;
import org.slf4j.Logger;
import java.util.concurrent.Executor;
/**
* This limits the number of threads that are used at maximum. Thread creation can be very heavy for the CPU and
* context switching between threads too. However, we need many threads for blocking HTTP and database calls.
* Nevertheless, this number can be further limited, because the number of actually working database threads
* is limited by the size of our database pool. The goal is to separate concerns into processing and blocking only
* threads.
*/
public class AsyncScheduler extends AbstractAsyncScheduler {
public AsyncScheduler(Logger logger, Executor processingPool) {
super(logger, processingPool);
logger.info("Using legacy platform scheduler for using an older Java version. "
+ "Upgrade Java to 21+ for improved performance");
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -26,7 +26,6 @@
package com.github.games647.fastlogin.core.shared;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.craftapi.resolver.Options;
import com.github.games647.craftapi.resolver.http.RotatingProxySelector;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.ProxyAgnosticMojangResolver;
@@ -49,12 +48,13 @@ import net.md_5.bungee.config.YamlConfiguration;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
@@ -78,10 +78,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
private static final long MAX_EXPIRE_RATE = 1_000_000;
private final Map<String, String> localeMessages = new ConcurrentHashMap<>();
private final ConcurrentMap<String, Object> pendingLogin = CommonUtil.buildCache(
Duration.ofMinutes(5), -1
);
private final ConcurrentMap<String, Object> pendingLogin = CommonUtil.buildCache(5, -1);
private final Collection<UUID> pendingConfirms = new HashSet<>();
private final T plugin;
@@ -120,35 +117,30 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
return;
}
Options resolverOptions = new Options();
resolverOptions.setMaxNameRequests(config.getInt("mojang-request-limit", 600));
// Initialize the resolver based on the config parameter
this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false)
? new ProxyAgnosticMojangResolver() : new MojangResolver();
antiBot = createAntiBotService(config.getSection("anti-bot"));
Set<Proxy> proxies = config.getStringList("proxies")
.stream()
.map(proxy -> proxy.split(":"))
.map(proxy -> new InetSocketAddress(proxy[0], Integer.parseInt(proxy[1])))
.map(sa -> new Proxy(Type.HTTP, sa))
.collect(toSet());
if (!proxies.isEmpty()) {
resolverOptions.setProxySelector(new RotatingProxySelector(proxies));
Collection<InetAddress> addresses = new HashSet<>();
for (String localAddress : config.getStringList("ip-addresses")) {
try {
addresses.add(InetAddress.getByName(localAddress.replace('-', '.')));
} catch (UnknownHostException ex) {
plugin.getLog().error("IP-Address is unknown to us", ex);
}
}
// TODO: Not available currently in craftapi?
// Collection<InetAddress> addresses = new HashSet<>();
// for (String localAddress : config.getStringList("ip-addresses")) {
// try {
// addresses.add(InetAddress.getByName(localAddress.replace('-', '.')));
// } catch (UnknownHostException ex) {
// plugin.getLog().error("IP-Address is unknown to us", ex);
// }
// }
// resolver.setOutgoingAddresses(addresses);
// Initialize the resolver based on the config parameter
this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false)
? new ProxyAgnosticMojangResolver(resolverOptions) : new MojangResolver(resolverOptions);
antiBot = createAntiBotService(config.getSection("anti-bot"));
resolver.setMaxNameRequests(config.getInt("mojang-request-limit"));
resolver.setProxySelector(new RotatingProxySelector(proxies));
resolver.setOutgoingAddresses(addresses);
}
private AntiBotService createAntiBotService(Configuration botSection) {
@@ -280,16 +272,8 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
this.passwordGenerator = passwordGenerator;
}
public void addLoginAttempt(String ip, String username) {
pendingLogin.put(ip + username, new Object());
}
public boolean hasFailedLogin(String ip, String username) {
if (!config.get("secondAttemptCracked", false)) {
return false;
}
return pendingLogin.remove(ip + username) != null;
public ConcurrentMap<String, Object> getPendingLogin() {
return pendingLogin;
}
public Collection<UUID> getPendingConfirms() {
@@ -300,7 +284,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
return authPlugin;
}
public AntiBotService getAntiBotService() {
public AntiBotService getAntiBot() {
return antiBot;
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -33,7 +33,6 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
@@ -62,9 +61,9 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
this.username = getName(player);
//load values from config.yml
autoLoginFloodgate = core.getConfig().get("autoLoginFloodgate").toString().toLowerCase(Locale.ROOT);
autoRegisterFloodgate = core.getConfig().get("autoRegisterFloodgate").toString().toLowerCase(Locale.ROOT);
allowNameConflict = core.getConfig().get("allowFloodgateNameConflict").toString().toLowerCase(Locale.ROOT);
autoLoginFloodgate = core.getConfig().get("autoLoginFloodgate").toString().toLowerCase();
autoRegisterFloodgate = core.getConfig().get("autoRegisterFloodgate").toString().toLowerCase();
allowNameConflict = core.getConfig().get("allowFloodgateNameConflict").toString().toLowerCase();
}
@Override
@@ -81,47 +80,13 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
}
profile = core.getStorage().loadProfile(username);
if (profile.isExistingPlayer()) {
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 {
//maybe Bungee without auth plugin
if (authPlugin == null) {
if (profile != null) {
isRegistered = profile.isOnlinemodePreferred();
isRegistered = profile.isPremium();
} else {
isRegistered = false;
}
@@ -154,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

View File

@@ -1,86 +0,0 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 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 final 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;
}
}
}

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -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;
@@ -81,7 +81,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
//update only on success to prevent corrupt data
if (playerProfile != null) {
playerProfile.setId(session.getUuid());
playerProfile.setOnlinemodePreferred(true);
playerProfile.setPremium(true);
storage.save(playerProfile);
}
@@ -91,7 +91,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
} else if (playerProfile != null) {
//cracked player
playerProfile.setId(null);
playerProfile.setOnlinemodePreferred(false);
playerProfile.setPremium(false);
storage.save(playerProfile);
}
} catch (Exception ex) {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -48,88 +48,73 @@ 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);
StoredProfile profile = core.getStorage().loadProfile(username);
if (profile == null) {
return;
}
//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
//perform Bedrock specific checks and skip Java checks, if they are not 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
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);
Configuration config = core.getConfig();
String ip = source.getAddress().getAddress().getHostAddress();
profile.setLastIp(ip);
if (profile.isExistingPlayer()) {
if (profile.isOnlinemodePreferred()) {
core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username);
requestPremiumLogin(source, profile, username, true);
} else {
if (isValidUsername(source, profile)) {
startCrackedSession(source, profile, username);
}
}
} else {
performNewPlayerLogin(username, source, ip, profile);
}
}
private void performNewPlayerLogin(String username, S source, String ip, StoredProfile profile) {
try {
if (core.hasFailedLogin(ip, username)) {
core.getPlugin().getLog().info("Second attempt login -> cracked {}", username);
if (profile.isSaved()) {
if (profile.isPremium()) {
core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username);
requestPremiumLogin(source, profile, username, true);
} else {
if (isValidUsername(source, profile)) {
startCrackedSession(source, profile, username);
}
}
} else {
if (core.getPendingLogin().remove(ip + username) != null && config.get("secondAttemptCracked", false)) {
core.getPlugin().getLog().info("Second attempt login -> cracked {}", username);
//first login request failed so make a cracked session
startCrackedSession(source, profile, username);
return;
}
Configuration config = core.getConfig();
Optional<Profile> premiumUUID = Optional.empty();
if (config.get("nameChangeCheck", false) || config.get("autoRegister", false)) {
premiumUUID = core.getResolver().findProfile(username);
}
if (!premiumUUID.isPresent()
|| (!isNameChanged(source, username, premiumUUID.get())
&& !isUsernameAvailable(source, username, profile))) {
//nothing detected the player as premium -> start a cracked session
if (core.getConfig().get("switchMode", false)) {
source.kick(core.getMessage("switch-kick-message"));
//first login request failed so make a cracked session
startCrackedSession(source, profile, username);
return;
}
startCrackedSession(source, profile, username);
Optional<Profile> premiumUUID = Optional.empty();
if (config.get("nameChangeCheck", false) || config.get("autoRegister", false)) {
premiumUUID = core.getResolver().findProfile(username);
}
if (!premiumUUID.isPresent()
|| (!checkNameChange(source, username, premiumUUID.get())
&& !checkPremiumName(source, username, profile))) {
//nothing detected the player as premium -> start a cracked session
if (core.getConfig().get("switchMode", false)) {
source.kick(core.getMessage("switch-kick-message"));
return;
}
startCrackedSession(source, profile, username);
}
}
} catch (RateLimitException rateLimitEx) {
core.getPlugin().getLog().error("Mojang's rate limit reached for {}. The public IPv4 address of this"
+ " server issued more than 600 Name -> UUID requests within 10 minutes. After those 10"
+ " minutes we can make requests again.", username);
+ " server issued more than 600 Name -> UUID requests within 10 minutes. After those 10"
+ " minutes we can make requests again.", username);
} catch (Exception ex) {
core.getPlugin().getLog().error("Failed to check premium state for {}", username, ex);
core.getPlugin().getLog().error("Failed to check premium state of {}", username, ex);
}
}
protected boolean isValidUsername(LoginSource source, StoredProfile profile) {
protected boolean isValidUsername(LoginSource source, StoredProfile profile) throws Exception {
if (bedrockService != null && bedrockService.isUsernameForbidden(profile)) {
core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player");
source.kick("Your username contains illegal characters");
@@ -139,7 +124,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
return true;
}
private boolean isUsernameAvailable(S source, String username, StoredProfile profile) throws Exception {
private boolean checkPremiumName(S source, String username, StoredProfile profile) throws Exception {
core.getPlugin().getLog().info("GameProfile {} uses a premium username", username);
if (core.getConfig().get("autoRegister", false) && (authHook == null || !authHook.isRegistered(username))) {
requestPremiumLogin(source, profile, username, false);
@@ -149,17 +134,11 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
return false;
}
private boolean isNameChanged(S source, String username, Profile profile) {
private boolean checkNameChange(S source, String username, Profile profile) {
//user not exists in the db
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);

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -61,7 +61,6 @@ public abstract class LoginSession {
}
/**
* Check if user needs registration once login is successful
* @return This value is always false if we authenticate the player with a cracked authentication
*/
public synchronized boolean needsRegistration() {

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 games647 and contributors
* 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
@@ -31,7 +31,7 @@ public interface LoginSource {
void enableOnlinemode() throws Exception;
void kick(String message);
void kick(String message) throws Exception;
InetSocketAddress getAddress();
}

Some files were not shown because too many files have changed in this diff Show More