forked from TuxCoding/FastLogin
Compare commits
89 Commits
add-postgr
...
main
Author | SHA1 | Date | |
---|---|---|---|
65a379c3c2 | |||
2ff6547552 | |||
c3233b2c67 | |||
f86c918a8b | |||
001cf3237b | |||
c28c634351 | |||
4550562465 | |||
2308d98dcd | |||
063b6a9405 | |||
1b45b8d2be | |||
8be0de4781 | |||
d06c44041d | |||
69fa341188 | |||
e1ba698f28 | |||
7bf613c8b4 | |||
1c194280b1 | |||
5803a34f84 | |||
86c4f48ec6 | |||
06e6741493 | |||
98da5a36da | |||
3bd9e60783 | |||
568ad7a621 | |||
1464ef2952 | |||
46239c9ffc | |||
083068b856 | |||
dd2aa922d7 | |||
b77ea285e5 | |||
f8f0e7ac7a | |||
927f09af67 | |||
9dee4e56a1 | |||
4dd6b9ade4 | |||
51efb9d62d | |||
1a56741112 | |||
7f488498cf | |||
9a40cf0afb | |||
2d177e3df5 | |||
bdd7af8290 | |||
29100b5376 | |||
bcb1893176 | |||
5fb6308130 | |||
a33f53e259 | |||
fb6209d26c | |||
829c70a51b | |||
2876448e0c | |||
2b60153f8a | |||
54b49eb6be | |||
be2ec1e5a8 | |||
e9643ee3e2 | |||
f1b780c398 | |||
33d3c751b9 | |||
00c0bd3b7b | |||
492a17e7de | |||
c063e7b58d | |||
0c64597ff0 | |||
9c06401e69 | |||
1f9253895c | |||
41a23bb292 | |||
756b777056 | |||
204d25a739 | |||
07e19b590a | |||
64d291556a | |||
bb78043d64 | |||
7b6d2062cf | |||
3473611b90 | |||
9fabc69ba9 | |||
5a782137af | |||
4068fd06db | |||
1419b7d357 | |||
690eabaa5e | |||
caf5188246 | |||
c905ca3d33 | |||
47b6835f37 | |||
884a4e0d65 | |||
0ac8481d92 | |||
f0209170c7 | |||
e63642b146 | |||
d58ef6b0a1 | |||
8e35c5df90 | |||
cf4d19aeca | |||
7479c8be87 | |||
1889c2605e | |||
3925b66511 | |||
3f47356d35 | |||
20c2126e53 | |||
e1335dccfe | |||
b9e94d3020 | |||
896e250fa2 | |||
815ff39c96 | |||
4100daa22a |
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -12,10 +12,6 @@ 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
|
||||
|
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@ -10,10 +10,10 @@ updates:
|
||||
interval: "monthly"
|
||||
|
||||
# Maven project
|
||||
- package-ecosystem: maven
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
interval: "monthly"
|
||||
|
||||
groups:
|
||||
production-dependencies:
|
||||
@ -30,6 +30,3 @@ updates:
|
||||
# HikariCP dropped Java 8 support with 5.0
|
||||
- dependency-name: "com.zaxxer:HikariCP"
|
||||
update-types: ["version-update:semver-major"]
|
||||
# SnakeYAML has breaking changes with 2.0
|
||||
- dependency-name: "org.yaml:snakeyaml"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
25
.github/release.yml
vendored
Normal file
25
.github/release.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# 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:
|
||||
- "*"
|
3
.github/workflows/codeql-analysis.yml
vendored
3
.github/workflows/codeql-analysis.yml
vendored
@ -25,8 +25,7 @@ jobs:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
# Only allow write for security, then all others default to read only
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
|
26
.github/workflows/maven.yml
vendored
26
.github/workflows/maven.yml
vendored
@ -21,7 +21,8 @@ jobs:
|
||||
# Environment image - always use the newest OS
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
# With at least one permission given, all default to read
|
||||
contents: read
|
||||
|
||||
# Run steps
|
||||
steps:
|
||||
@ -42,6 +43,25 @@ jobs:
|
||||
# ignore snapshot updates, because they are likely to have breaking changes, enforce checksums
|
||||
run: mvn test --batch-mode --threads 2.0C --no-snapshot-updates --strict-checksums --file pom.xml
|
||||
|
||||
- name: Update dependency graph
|
||||
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@v4
|
||||
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@v4.0.0
|
||||
uses: advanced-security/maven-dependency-submission-action@v5.0.0
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 games647 and contributors
|
||||
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
|
||||
|
33
README.md
33
README.md
@ -1,5 +1,7 @@
|
||||
# FastLogin
|
||||
|
||||

|
||||
|
||||
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).
|
||||
|
||||
@ -8,14 +10,11 @@ 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 support
|
||||
* BungeeCord/Velocity 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
|
||||
@ -33,7 +32,11 @@ 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: https://ci.codemc.org/job/Games647/job/FastLogin/
|
||||
~~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)
|
||||
|
||||
|
||||
|
||||
***
|
||||
|
||||
@ -46,6 +49,7 @@ You can download them from here: https://ci.codemc.org/job/Games647/job/FastLogi
|
||||
|
||||
fastlogin.bukkit.command.premium
|
||||
fastlogin.bukkit.command.cracked
|
||||
|
||||
fastlogin.command.premium.other
|
||||
fastlogin.command.cracked.other
|
||||
|
||||
@ -60,13 +64,15 @@ Possible values: `Premium`, `Cracked`, `Unknown`
|
||||
|
||||
## Requirements
|
||||
|
||||
* Java 17+ (Recommended)
|
||||
* Java: 21+ recommended for improved multi-threading code by FastLogin
|
||||
* Spigot: 8+
|
||||
* BungeeCord and Velocity: 17+
|
||||
* Server software in offlinemode:
|
||||
* Spigot (or a fork e.g. Paper) 1.8.8+
|
||||
* Protocol plugin:
|
||||
* [ProtocolLib 5.1+](https://www.spigotmc.org/resources/protocollib.1997/) or
|
||||
* [ProtocolLib 5.3+ with development build above 720](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
|
||||
* Latest BungeeCord (or a fork e.g. Waterfall) or Velocity proxy
|
||||
* An auth plugin.
|
||||
|
||||
### Supported auth plugins
|
||||
@ -85,7 +91,6 @@ 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
|
||||
|
||||
@ -101,8 +106,8 @@ This plugin performs network requests to:
|
||||
### Spigot/Paper
|
||||
|
||||
1. Download and install ProtocolLib/ProtocolSupport
|
||||
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
|
||||
2. Download and install `FastLoginBukkit`
|
||||
3. Set your server in offline mode by setting the value `onlinemode` in your server.properties to `false`
|
||||
|
||||
### BungeeCord/Waterfall or Velocity
|
||||
|
||||
@ -117,10 +122,10 @@ 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: `com.mysql.jdbc.Driver` for MySQL/MariaDB/PostgreSQL
|
||||
* Velocity: `fastlogin.mariadb.jdbc.Driver` for MySQL/MariaDB/PostgreSQL
|
||||
* BungeeCord: `mysql` for MySQL/MariaDB
|
||||
* Velocity: `mariadb` for MySQL/MariaDB
|
||||
* Note the embedded file storage SQLite is not available
|
||||
* MySQL/MariaDB/PostgreSQL requires an external database server running. Check your server provider if there is one available
|
||||
* MySQL/MariaDB requires an external database server running. Check your server provider if there is one available
|
||||
or install one.
|
||||
6. Set proxy and Spigot in offline mode by setting the value `onlinemode` in your `config.yml` to false
|
||||
7. You should *always* configure the firewall for your Spigot server so that it's only accessible through your proxy
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 games647 and contributors
|
||||
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
|
||||
@ -30,7 +30,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<properties>
|
||||
<nettyVersion>4.1.79.Final</nettyVersion>
|
||||
<maven.compiler.release>8</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
@ -50,7 +50,7 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
@ -98,7 +98,6 @@
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/MANIFEST.MF</exclude>
|
||||
<exclude>**/module-info.class</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
@ -117,19 +116,16 @@
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<!-- PaperSpigot API and PaperLib -->
|
||||
<!-- PaperSpigot API, PaperLib, datafixupper and bungeecord-chat -->
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
<url>https://repo.papermc.io/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 -->
|
||||
@ -168,18 +164,11 @@
|
||||
<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.19-R0.1-SNAPSHOT</version>
|
||||
<version>1.21.6-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<!-- Use our own newer api version -->
|
||||
<exclusions>
|
||||
@ -187,13 +176,25 @@
|
||||
<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>5.0.28</version>
|
||||
<version>7.1.15</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -207,7 +208,7 @@
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.3.0</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -278,7 +279,7 @@
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.5</version>
|
||||
<version>2.11.6</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
@ -293,7 +294,7 @@
|
||||
<dependency>
|
||||
<groupId>fr.xephi</groupId>
|
||||
<artifactId>authme</artifactId>
|
||||
<version>5.6.0-beta2</version>
|
||||
<version>5.6.0</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
@ -347,6 +348,22 @@
|
||||
</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>
|
||||
@ -378,29 +395,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
<version>1.77</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>
|
||||
<version>1.80</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -47,7 +47,6 @@ 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,
|
||||
@ -109,7 +108,7 @@ public class BukkitLoginSession extends LoginSession {
|
||||
*
|
||||
* @param verified whether the player has valid session
|
||||
*/
|
||||
public synchronized void setVerified(boolean verified) {
|
||||
public synchronized void setVerifiedPremium(boolean verified) {
|
||||
this.verified = verified;
|
||||
}
|
||||
|
||||
@ -118,7 +117,7 @@ public class BukkitLoginSession extends LoginSession {
|
||||
*
|
||||
* @return whether the player has a valid session
|
||||
*/
|
||||
public synchronized boolean isVerified() {
|
||||
public synchronized boolean isVerifiedPremium() {
|
||||
return verified;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -25,7 +25,7 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
|
||||
import com.github.games647.fastlogin.core.AsyncScheduler;
|
||||
import com.github.games647.fastlogin.core.scheduler.AsyncScheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -31,6 +31,7 @@ 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;
|
||||
@ -133,6 +134,13 @@ 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;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -28,6 +28,7 @@ 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;
|
||||
@ -36,6 +37,7 @@ 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;
|
||||
@ -53,6 +55,7 @@ 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;
|
||||
@ -65,7 +68,10 @@ 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(1, -1);
|
||||
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(
|
||||
Duration.ofMinutes(1), -1
|
||||
);
|
||||
|
||||
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
|
||||
private final Logger logger;
|
||||
|
||||
@ -111,10 +117,11 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
return;
|
||||
}
|
||||
|
||||
AntiBotService antiBotService = core.getAntiBotService();
|
||||
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
|
||||
pluginManager.registerEvents(new ProtocolSupportListener(this, core.getAntiBot()), this);
|
||||
pluginManager.registerEvents(new ProtocolSupportListener(this, antiBotService), this);
|
||||
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
|
||||
ProtocolLibListener.register(this, core.getAntiBot(), core.getConfig().getBoolean("verifyClientKeys"));
|
||||
ProtocolLibListener.register(this, antiBotService, 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")) {
|
||||
@ -137,9 +144,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
pluginManager.registerEvents(new PaperCacheListener(this), this);
|
||||
}
|
||||
|
||||
//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)));
|
||||
registerCommands();
|
||||
|
||||
if (pluginManager.isPluginEnabled("PlaceholderAPI")) {
|
||||
premiumPlaceholder = new PremiumPlaceholder(this);
|
||||
@ -147,6 +152,13 @@ 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);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -74,11 +74,13 @@ 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();
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -30,6 +30,7 @@ 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;
|
||||
@ -57,21 +58,31 @@ 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.isPremium()) {
|
||||
if (profile.isOnlinemodePreferred()) {
|
||||
plugin.getCore().sendLocaleMessage("remove-premium", sender);
|
||||
|
||||
profile.setPremium(false);
|
||||
profile.setOnlinemodePreferred(false);
|
||||
profile.setId(null);
|
||||
plugin.getScheduler().runAsync(() -> {
|
||||
plugin.getCore().getStorage().save(profile);
|
||||
plugin.getServer().getPluginManager().callEvent(
|
||||
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
plugin.getCore().sendLocaleMessage("not-premium", sender);
|
||||
@ -95,16 +106,16 @@ public class CrackedCommand extends ToggleCommand {
|
||||
}
|
||||
|
||||
//existing player is already cracked
|
||||
if (profile.isSaved() && !profile.isPremium()) {
|
||||
if (profile.isExistingPlayer() && !profile.isOnlinemodePreferred()) {
|
||||
plugin.getCore().sendLocaleMessage("not-premium-other", sender);
|
||||
} else {
|
||||
plugin.getCore().sendLocaleMessage("remove-premium", sender);
|
||||
|
||||
profile.setPremium(false);
|
||||
profile.setOnlinemodePreferred(false);
|
||||
plugin.getScheduler().runAsync(() -> {
|
||||
plugin.getCore().getStorage().save(profile);
|
||||
plugin.getServer().getPluginManager().callEvent(
|
||||
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
|
||||
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_OTHER));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -68,7 +68,8 @@ public class PremiumCommand extends ToggleCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID id = ((Player) sender).getUniqueId();
|
||||
Player player = (Player) sender;
|
||||
UUID id = player.getUniqueId();
|
||||
if (plugin.getConfig().getBoolean("premium-warning") && !plugin.getCore().getPendingConfirms().contains(id)) {
|
||||
sender.sendMessage(plugin.getCore().getMessage("premium-warning"));
|
||||
plugin.getCore().getPendingConfirms().add(id);
|
||||
@ -78,18 +79,25 @@ public class PremiumCommand extends ToggleCommand {
|
||||
plugin.getCore().getPendingConfirms().remove(id);
|
||||
//todo: load async
|
||||
StoredProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName());
|
||||
if (profile.isPremium()) {
|
||||
if (profile.isOnlinemodePreferred()) {
|
||||
plugin.getCore().sendLocaleMessage("already-exists", sender);
|
||||
} else {
|
||||
//todo: resolve uuid
|
||||
profile.setPremium(true);
|
||||
profile.setOnlinemodePreferred(true);
|
||||
plugin.getScheduler().runAsync(() -> {
|
||||
plugin.getCore().getStorage().save(profile);
|
||||
plugin.getServer().getPluginManager().callEvent(
|
||||
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_SELF));
|
||||
});
|
||||
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_SELF)
|
||||
);
|
||||
|
||||
plugin.getCore().sendLocaleMessage("add-premium", sender);
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,15 +117,16 @@ public class PremiumCommand extends ToggleCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile.isPremium()) {
|
||||
if (profile.isOnlinemodePreferred()) {
|
||||
plugin.getCore().sendLocaleMessage("already-exists-other", sender);
|
||||
} else {
|
||||
//todo: resolve uuid
|
||||
profile.setPremium(true);
|
||||
profile.setOnlinemodePreferred(true);
|
||||
plugin.getScheduler().runAsync(() -> {
|
||||
plugin.getCore().getStorage().save(profile);
|
||||
plugin.getServer().getPluginManager().callEvent(
|
||||
new BukkitFastLoginPremiumToggleEvent(profile, PremiumToggleReason.COMMAND_OTHER));
|
||||
new BukkitFastLoginPremiumToggleEvent(sender, profile, PremiumToggleReason.COMMAND_OTHER)
|
||||
);
|
||||
});
|
||||
|
||||
plugin.getCore().sendLocaleMessage("add-premium-other", sender);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -27,6 +27,7 @@ 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;
|
||||
@ -34,11 +35,15 @@ 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(StoredProfile profile, PremiumToggleReason reason) {
|
||||
public BukkitFastLoginPremiumToggleEvent(CommandSender invoker, StoredProfile profile, PremiumToggleReason reason) {
|
||||
super(true);
|
||||
|
||||
this.invoker = invoker;
|
||||
this.profile = profile;
|
||||
this.reason = reason;
|
||||
}
|
||||
@ -48,6 +53,13 @@ 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;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -45,9 +45,9 @@ import java.lang.reflect.Field;
|
||||
* <p>
|
||||
* Project page:
|
||||
* <p>
|
||||
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/authme-reloaded/">...</a>
|
||||
* <a href="https://dev.bukkit.org/bukkit-plugins/authme-reloaded/">Bukkit</a>
|
||||
* <p>
|
||||
* Spigot: <a href="https://www.spigotmc.org/resources/authme-reloaded.6269/">...</a>
|
||||
* <a href="https://www.spigotmc.org/resources/authme-reloaded.6269/">Spigot</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.isVerified()) {
|
||||
if (session != null && session.isVerifiedPremium()) {
|
||||
restoreSessionEvent.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -46,7 +46,7 @@ import java.util.concurrent.Future;
|
||||
* <p>
|
||||
* Project page:
|
||||
* <p>
|
||||
* Bukkit: <a href="https://dev.bukkit.org/server-mods/crazylogin/">...</a>
|
||||
* <a href="https://dev.bukkit.org/server-mods/crazylogin/">Bukkit</a>
|
||||
*/
|
||||
public class CrazyLoginHook implements AuthPlugin<Player> {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -39,9 +39,9 @@ import org.bukkit.entity.Player;
|
||||
* <p>
|
||||
* Project page:
|
||||
* <p>
|
||||
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/loginsecurity/">...</a>
|
||||
* <a href="https://dev.bukkit.org/bukkit-plugins/loginsecurity/">Bukkit</a>
|
||||
* <p>
|
||||
* Spigot: <a href="https://www.spigotmc.org/resources/loginsecurity.19362/">...</a>
|
||||
* <a href="https://www.spigotmc.org/resources/loginsecurity.19362/">Spigot</a>
|
||||
*/
|
||||
public class LoginSecurityHook implements AuthPlugin<Player> {
|
||||
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -38,9 +38,9 @@ import java.util.concurrent.Future;
|
||||
/**
|
||||
* Project page:
|
||||
* <p>
|
||||
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/">...</a>
|
||||
* <a href="https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/">Bukkit</a>
|
||||
* <p>
|
||||
* Spigot: <a href="https://www.spigotmc.org/resources/ultraauth.17044/">...</a>
|
||||
* <a href="https://www.spigotmc.org/resources/ultraauth.17044/">Spigot</a>
|
||||
*/
|
||||
public class UltraAuthHook implements AuthPlugin<Player> {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -40,7 +40,7 @@ import java.util.concurrent.Future;
|
||||
* <p>
|
||||
* Project page:
|
||||
* <p>
|
||||
* Bukkit: <a href="https://dev.bukkit.org/bukkit-plugins/xauth/">...</a>
|
||||
* <a href="https://dev.bukkit.org/bukkit-plugins/xauth/">Bukkit</a>
|
||||
*/
|
||||
public class XAuthHook implements AuthPlugin<Player> {
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -123,7 +123,7 @@ public class BungeeListener implements PluginMessageListener {
|
||||
}
|
||||
|
||||
private void startLoginTaskIfReady(Player player, BukkitLoginSession session) {
|
||||
session.setVerified(true);
|
||||
session.setVerifiedPremium(true);
|
||||
plugin.putSession(player.spigot().getRawAddress(), session);
|
||||
|
||||
// only start a new login task if the join event fired earlier. This event then didn't
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -90,6 +90,7 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -31,7 +31,6 @@ 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;
|
||||
@ -41,6 +40,7 @@ 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,6 +53,7 @@ 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;
|
||||
@ -198,9 +199,9 @@ final class EncryptionUtil {
|
||||
|
||||
private static PublicKey loadMojangSessionKey()
|
||||
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
val keyUrl = FastLoginBukkit.class.getClassLoader().getResource("yggdrasil_session_pubkey.der");
|
||||
val keyData = Resources.toByteArray(keyUrl);
|
||||
val keySpec = new X509EncodedKeySpec(keyData);
|
||||
URL keyUrl = FastLoginBukkit.class.getClassLoader().getResource("yggdrasil_session_pubkey.der");
|
||||
byte[] keyData = Resources.toByteArray(keyUrl);
|
||||
KeySpec keySpec = new X509EncodedKeySpec(keyData);
|
||||
|
||||
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -97,7 +97,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
|
||||
}
|
||||
|
||||
String ip = player.getAddress().getAddress().getHostAddress();
|
||||
core.getPendingLogin().put(ip + username, new Object());
|
||||
core.addLoginAttempt(ip, username);
|
||||
|
||||
byte[] verify = source.getVerifyToken();
|
||||
ClientPublicKey clientKey = source.getClientKey();
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -30,15 +30,16 @@ 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.PacketFilterManager;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||
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.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;
|
||||
@ -48,9 +49,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;
|
||||
@ -73,7 +74,6 @@ 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,7 +92,6 @@ 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) {
|
||||
@ -112,45 +111,66 @@ public class ProtocolLibListener extends PacketAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getLog().info("New packet {} from {}", packetEvent.getPacketType(), packetEvent.getPlayer());
|
||||
|
||||
Player sender = packetEvent.getPlayer();
|
||||
PacketType packetType = packetEvent.getPacketType();
|
||||
if (packetType == START) {
|
||||
PacketType packetType = getOverriddenType(packetEvent.getPacketType());
|
||||
|
||||
if (plugin.getFloodgateService() != null) {
|
||||
boolean success = processFloodgateTasks(packetEvent);
|
||||
// don't continue execution if the player was kicked by Floodgate
|
||||
if (!success) {
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
} catch (FieldAccessException fieldAccessEx) {
|
||||
plugin.getLog().error("Failed to parse packet {}", packetEvent.getPacketType(), fieldAccessEx);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -222,11 +242,12 @@ public class ProtocolLibListener extends PacketAdapter {
|
||||
PacketContainer packet = packetEvent.getPacket();
|
||||
Optional<ClientPublicKey> clientKey;
|
||||
if (new MinecraftVersion(1, 19, 3).atOrAbove()) {
|
||||
// public key sent separate
|
||||
// public key is sent separate
|
||||
clientKey = Optional.empty();
|
||||
} else {
|
||||
val profileKey = packet.getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter())
|
||||
.optionRead(0);
|
||||
Optional<Optional<WrappedProfileKeyData>> profileKey = packet.getOptionals(
|
||||
BukkitConverters.getWrappedPublicKeyDataConverter()
|
||||
).optionRead(0);
|
||||
|
||||
clientKey = profileKey.flatMap(Function.identity()).flatMap(data -> {
|
||||
Instant expires = data.getExpireTime();
|
||||
@ -247,7 +268,6 @@ public class ProtocolLibListener extends PacketAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
|
||||
|
||||
packetEvent.getAsyncMarker().incrementProcessingDelay();
|
||||
@ -275,18 +295,19 @@ public class ProtocolLibListener extends PacketAdapter {
|
||||
return profile.getName();
|
||||
}
|
||||
|
||||
private static PlayerInjectionHandler getHandler() {
|
||||
PacketFilterManager manager = (PacketFilterManager) ProtocolLibrary.getProtocolManager();
|
||||
FieldAccessor accessor = Accessors.getFieldAccessor(manager.getClass(), PlayerInjectionHandler.class, true);
|
||||
return (PlayerInjectionHandler) accessor.get(manager);
|
||||
}
|
||||
|
||||
private FloodgatePlayer getFloodgatePlayer(Player player) {
|
||||
Channel channel = handler.getChannel(player);
|
||||
Channel channel = getChannel(player);
|
||||
AttributeKey<FloodgatePlayer> floodgateAttribute = AttributeKey.valueOf("floodgate-player");
|
||||
return channel.attr(floodgateAttribute).get();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reimplementation of the tasks injected Floodgate in ProtocolLib that are not run due to a bug
|
||||
* @see <a href="https://github.com/GeyserMC/Floodgate/issues/143">Issue Floodgate#143</a>
|
||||
@ -303,7 +324,7 @@ public class ProtocolLibListener extends PacketAdapter {
|
||||
}
|
||||
|
||||
// kick the player, if necessary
|
||||
Channel channel = handler.getChannel(packetEvent.getPlayer());
|
||||
Channel channel = getChannel(packetEvent.getPlayer());
|
||||
AttributeKey<String> kickMessageAttribute = AttributeKey.valueOf("floodgate-kick-message");
|
||||
String kickMessage = channel.attr(kickMessageAttribute).get();
|
||||
if (kickMessage != null) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -51,7 +51,6 @@ 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) {
|
||||
@ -72,7 +71,7 @@ class ProtocolLibLoginSource implements LoginSource {
|
||||
*/
|
||||
PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN);
|
||||
|
||||
newPacket.getStrings().write(0, serverId);
|
||||
newPacket.getStrings().write(0, "");
|
||||
StructureModifier<PublicKey> keyModifier = newPacket.getSpecificModifier(PublicKey.class);
|
||||
int verifyField = 0;
|
||||
if (keyModifier.getFields().isEmpty()) {
|
||||
@ -84,6 +83,8 @@ 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);
|
||||
@ -115,10 +116,6 @@ class ProtocolLibLoginSource implements LoginSource {
|
||||
return clientKey;
|
||||
}
|
||||
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
public byte[] getVerifyToken() {
|
||||
return verifyToken.clone();
|
||||
}
|
||||
@ -128,7 +125,6 @@ class ProtocolLibLoginSource implements LoginSource {
|
||||
return this.getClass().getSimpleName() + '{'
|
||||
+ "player=" + player
|
||||
+ ", random=" + random
|
||||
+ ", serverId='" + serverId + '\''
|
||||
+ ", verifyToken=" + Arrays.toString(verifyToken)
|
||||
+ '}';
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -28,6 +28,7 @@ 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;
|
||||
@ -49,7 +50,6 @@ 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,7 +72,6 @@ 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 Class<?> ENCRYPTION_CLASS;
|
||||
private static final String ADDRESS_VERIFY_WARNING = "This indicates the use of reverse-proxy like HAProxy, "
|
||||
+ "TCPShield, BungeeCord, Velocity, etc. "
|
||||
+ "By default (configurable in the config) this plugin requests Mojang to verify the connecting IP "
|
||||
@ -81,12 +80,6 @@ public class VerifyResponseTask implements Runnable {
|
||||
+ "(keyword IP forwarding). This process will also be useful for other server "
|
||||
+ "features like IP banning, so that it doesn't ban the proxy IP.";
|
||||
|
||||
static {
|
||||
ENCRYPTION_CLASS = MinecraftReflection.getMinecraftClass(
|
||||
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
|
||||
);
|
||||
}
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private final PacketEvent packetEvent;
|
||||
private final KeyPair serverKey;
|
||||
@ -98,6 +91,8 @@ 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,
|
||||
@ -159,11 +154,11 @@ public class VerifyResponseTask implements Runnable {
|
||||
//user tried to fake an authentication
|
||||
disconnect(
|
||||
"invalid-session",
|
||||
"Session server rejected incoming connection for GameProfile {} ({}). Possible reasons are"
|
||||
"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"
|
||||
+ "2) Player is offline, but tried to bypass the authentication "
|
||||
+ "3) Client uses an outdated username for connecting (Fix: Restart client)",
|
||||
requestedUsername, address
|
||||
);
|
||||
@ -173,12 +168,12 @@ public class VerifyResponseTask implements Runnable {
|
||||
"The incoming request for player {} uses a local IP address",
|
||||
requestedUsername
|
||||
);
|
||||
plugin.getLog().warn(ADDRESS_VERIFY_WARNING);
|
||||
} else {
|
||||
plugin.getLog().warn("If you think this is an error, please verify that the incoming "
|
||||
+ "IP address {} is not associated with a server hosting company.", address);
|
||||
plugin.getLog().warn(ADDRESS_VERIFY_WARNING);
|
||||
}
|
||||
|
||||
plugin.getLog().warn(ADDRESS_VERIFY_WARNING);
|
||||
}
|
||||
} catch (IOException ioEx) {
|
||||
disconnect("error-kick", "Failed to connect to session server", ioEx);
|
||||
@ -200,7 +195,7 @@ public class VerifyResponseTask implements Runnable {
|
||||
|
||||
session.setVerifiedUsername(realUsername);
|
||||
session.setUuid(verification.getId());
|
||||
session.setVerified(true);
|
||||
session.setVerifiedPremium(true);
|
||||
|
||||
setPremiumUUID(session.getUuid());
|
||||
receiveFakeStartPacket(realUsername, session.getClientPublicKey(), session.getUuid());
|
||||
@ -223,34 +218,36 @@ public class VerifyResponseTask implements Runnable {
|
||||
|
||||
//try to get the networkManager from ProtocolLib
|
||||
private Object getNetworkManager() throws ClassNotFoundException {
|
||||
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
|
||||
NettyChannelInjector injectorContainer = (NettyChannelInjector) Accessors.getMethodAccessorOrNull(
|
||||
TemporaryPlayerFactory.class, "getInjectorFromPlayer", Player.class
|
||||
).invoke(null, player);
|
||||
|
||||
// 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);
|
||||
FieldAccessor accessor = Accessors.getFieldAccessorOrNull(
|
||||
NettyChannelInjector.class, "networkManager", Object.class
|
||||
);
|
||||
return accessor.get(injectorContainer);
|
||||
}
|
||||
|
||||
private boolean enableEncryption(SecretKey loginKey) throws IllegalArgumentException {
|
||||
plugin.getLog().info("Enabling onlinemode encryption for {}", player.getAddress());
|
||||
// Initialize method reflections
|
||||
if (encryptMethod == null) {
|
||||
if (encryptKeyMethod == null || encryptMethod == null) {
|
||||
Class<?> networkManagerClass = MinecraftReflection.getNetworkManagerClass();
|
||||
|
||||
try {
|
||||
// Try to get the old (pre MC 1.16.4) encryption method
|
||||
encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
|
||||
encryptKeyMethod = 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
|
||||
);
|
||||
|
||||
// Get the needed Cipher helper method (used to generate ciphers from login key)
|
||||
cipherMethod = FuzzyReflection.fromClass(ENCRYPTION_CLASS)
|
||||
cipherMethod = FuzzyReflection.fromClass(encryptionClass)
|
||||
.getMethodByParameters("a", int.class, Key.class);
|
||||
}
|
||||
}
|
||||
@ -259,9 +256,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 (cipherMethod == null) {
|
||||
if (encryptKeyMethod != null) {
|
||||
// Encrypt/decrypt packet flow, this behaviour is expected by the client
|
||||
encryptMethod.invoke(networkManager, loginKey);
|
||||
encryptKeyMethod.invoke(networkManager, loginKey);
|
||||
} else {
|
||||
// Create ciphers from login key
|
||||
Object decryptionCipher = cipherMethod.invoke(null, Cipher.DECRYPT_MODE, loginKey);
|
||||
@ -309,7 +306,7 @@ public class VerifyResponseTask implements Runnable {
|
||||
startPacket.getStrings().write(0, username);
|
||||
|
||||
EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
|
||||
val wrappedKey = Optional.ofNullable(clientKey).map(key ->
|
||||
Optional<WrappedProfileKeyData> wrappedKey = Optional.ofNullable(clientKey).map(key ->
|
||||
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
|
||||
);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -25,20 +25,38 @@
|
||||
*/
|
||||
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 {
|
||||
Instant expiry;
|
||||
PublicKey key;
|
||||
byte[] signature;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean isExpired(Instant verifyTimestamp) {
|
||||
return !verifyTimestamp.isBefore(expiry);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -101,7 +101,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
|
||||
BukkitLoginSession session = plugin.getSession(address);
|
||||
|
||||
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
|
||||
session.setVerified(true);
|
||||
session.setVerifiedPremium(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().getPendingLogin().put(ip + username, new Object());
|
||||
plugin.getCore().addLoginAttempt(ip, username);
|
||||
|
||||
BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile);
|
||||
plugin.putSession(source.getAddress(), playerSession);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -32,6 +32,7 @@ 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;
|
||||
@ -94,7 +95,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);
|
||||
XAuthHook.class, PasskyHook.class);
|
||||
|
||||
for (Class<? extends AuthPlugin<Player>> clazz : hooks) {
|
||||
String pluginName = clazz.getSimpleName();
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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.setVerified(isAutoAuthAllowed(autoLoginFloodgate));
|
||||
session.setVerifiedPremium(isAutoAuthAllowed(autoLoginFloodgate));
|
||||
|
||||
// run login task
|
||||
Runnable forceLoginTask = new ForceLoginTask(core.getPlugin().getCore(), player, session);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -103,6 +103,6 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
|
||||
|
||||
@Override
|
||||
public boolean isOnlineMode() {
|
||||
return session.isVerified();
|
||||
return session.isVerifiedPremium();
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ softdepend:
|
||||
- floodgate
|
||||
# Auth plugins
|
||||
- AuthMe
|
||||
- CrazyLogin
|
||||
- LoginSecurity
|
||||
- SodionAuth
|
||||
- xAuth
|
||||
- LogIt
|
||||
- UltraAuth
|
||||
- CrazyLogin
|
||||
- xAuth
|
||||
- Passky
|
||||
|
||||
commands:
|
||||
${project.parent.name}:
|
||||
@ -45,6 +45,11 @@ 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'
|
||||
@ -63,3 +68,7 @@ permissions:
|
||||
description: 'Label others as cracked'
|
||||
children:
|
||||
${project.artifactId}.command.cracked: true
|
||||
|
||||
${project.artifactId}.command.delete:
|
||||
description: 'Delete other players profile data'
|
||||
default: op
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -26,7 +26,7 @@
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
|
||||
import com.github.games647.fastlogin.core.CommonUtil;
|
||||
import lombok.val;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -37,12 +37,14 @@ class FastLoginBukkitTest {
|
||||
|
||||
@Test
|
||||
void testRGB() {
|
||||
val message = "&x00002a00002b&lText";
|
||||
val msg = CommonUtil.translateColorCodes(message);
|
||||
String message = "&x00002a00002b&lText";
|
||||
String msg = CommonUtil.translateColorCodes(message);
|
||||
assertEquals(msg, "§x00002a00002b§lText");
|
||||
|
||||
val components = TextComponent.fromLegacyText(msg);
|
||||
val expected = "{\"bold\":true,\"color\":\"#00a00b\",\"text\":\"Text\"}";
|
||||
@SuppressWarnings("deprecation")
|
||||
BaseComponent[] components = TextComponent.fromLegacyText(msg);
|
||||
String expected = "{\"bold\":true,\"color\":\"#00a00b\",\"text\":\"Text\"}";
|
||||
//noinspection deprecation
|
||||
assertEquals(ComponentSerializer.toString(components), expected);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -28,7 +28,6 @@ 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;
|
||||
@ -37,7 +36,7 @@ public class Base64Adapter extends TypeAdapter<byte[]> {
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, byte[] value) throws IOException {
|
||||
val encoded = Base64.getEncoder().encodeToString(value);
|
||||
String encoded = Base64.getEncoder().encodeToString(value);
|
||||
out.value(encoded);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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,6 +51,7 @@ 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;
|
||||
|
||||
@ -60,7 +61,7 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testVerifyToken() {
|
||||
val random = ThreadLocalRandom.current();
|
||||
Random random = ThreadLocalRandom.current();
|
||||
byte[] token = EncryptionUtil.generateVerifyToken(random);
|
||||
|
||||
assertAll(
|
||||
@ -88,10 +89,10 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testExpiredClientKey() throws Exception {
|
||||
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||
|
||||
// Client expires at the exact second mentioned, so use it for verification
|
||||
val expiredTimestamp = clientKey.expiry();
|
||||
Instant expiredTimestamp = clientKey.expiry();
|
||||
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp, null));
|
||||
}
|
||||
|
||||
@ -105,7 +106,7 @@ class EncryptionUtilTest {
|
||||
"client_keys/invalid_wrong_signature.json"
|
||||
})
|
||||
void testInvalidClientKey(String clientKeySource) throws Exception {
|
||||
val clientKey = ResourceLoader.loadClientKey(clientKeySource);
|
||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey(clientKeySource);
|
||||
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
|
||||
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp, null));
|
||||
@ -113,34 +114,34 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testValidClientKey() throws Exception {
|
||||
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
|
||||
assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValid191ClientKey() throws Exception {
|
||||
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
|
||||
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
|
||||
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
|
||||
val ownerPremiumId = UUID.fromString("0aaa2c13-922a-411b-b655-9b8c08404695");
|
||||
UUID ownerPremiumId = UUID.fromString("0aaa2c13-922a-411b-b655-9b8c08404695");
|
||||
assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, ownerPremiumId));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIncorrect191ClientOwner() throws Exception {
|
||||
val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
|
||||
val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json");
|
||||
Instant verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||
|
||||
val ownerPremiumId = UUID.fromString("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6");
|
||||
UUID ownerPremiumId = UUID.fromString("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6");
|
||||
assertFalse(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, ownerPremiumId));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecryptSharedSecret() throws Exception {
|
||||
KeyPair serverPair = EncryptionUtil.generateKeyPair();
|
||||
val serverPK = serverPair.getPublic();
|
||||
PublicKey serverPK = serverPair.getPublic();
|
||||
|
||||
SecretKey secretKey = generateSharedKey();
|
||||
byte[] encryptedSecret = encrypt(serverPK, secretKey.getEncoded());
|
||||
@ -152,7 +153,7 @@ class EncryptionUtilTest {
|
||||
private static byte[] encrypt(PublicKey receiverKey, byte... message)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||
IllegalBlockSizeException, BadPaddingException {
|
||||
val encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
|
||||
Cipher encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, receiverKey);
|
||||
return encryptCipher.doFinal(message);
|
||||
}
|
||||
@ -168,9 +169,9 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testServerIdHash() throws Exception {
|
||||
val serverId = "";
|
||||
val sharedSecret = generateSharedKey();
|
||||
val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||
String serverId = "";
|
||||
SecretKeySpec sharedSecret = generateSharedKey();
|
||||
PublicKey serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||
|
||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||
assertEquals(EncryptionUtil.getServerIdHashString(serverId, sharedSecret, serverPK), sessionHash);
|
||||
@ -185,7 +186,7 @@ class EncryptionUtilTest {
|
||||
// sha1.update(server's encoded public key from Encryption Request)
|
||||
// hash := sha1.hexdigest() # String of hex characters
|
||||
@SuppressWarnings("deprecation")
|
||||
val hasher = Hashing.sha1().newHasher();
|
||||
Hasher hasher = Hashing.sha1().newHasher();
|
||||
hasher.putString(serverId, StandardCharsets.US_ASCII);
|
||||
hasher.putBytes(sharedSecret.getEncoded());
|
||||
hasher.putBytes(serverPK.getEncoded());
|
||||
@ -198,9 +199,9 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testServerIdHashWrongSecret() throws Exception {
|
||||
val serverId = "";
|
||||
val sharedSecret = generateSharedKey();
|
||||
val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||
String serverId = "";
|
||||
SecretKeySpec sharedSecret = generateSharedKey();
|
||||
PublicKey serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||
|
||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||
assertNotEquals(EncryptionUtil.getServerIdHashString("", generateSharedKey(), serverPK), sessionHash);
|
||||
@ -208,12 +209,12 @@ class EncryptionUtilTest {
|
||||
|
||||
@Test
|
||||
void testServerIdHashWrongServerKey() {
|
||||
val serverId = "";
|
||||
val sharedSecret = generateSharedKey();
|
||||
val serverPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||
String serverId = "";
|
||||
SecretKeySpec sharedSecret = generateSharedKey();
|
||||
PublicKey serverPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||
|
||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||
val wrongPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||
PublicKey wrongPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||
assertNotEquals(EncryptionUtil.getServerIdHashString("", sharedSecret, wrongPK), sessionHash);
|
||||
}
|
||||
|
||||
@ -257,8 +258,8 @@ class EncryptionUtilTest {
|
||||
@Test
|
||||
void testNonce() throws Exception {
|
||||
byte[] expected = {1, 2, 3, 4};
|
||||
val serverKey = EncryptionUtil.generateKeyPair();
|
||||
val encryptedNonce = encrypt(serverKey.getPublic(), expected);
|
||||
KeyPair serverKey = EncryptionUtil.generateKeyPair();
|
||||
byte[] encryptedNonce = encrypt(serverKey.getPublic(), expected);
|
||||
|
||||
assertTrue(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce));
|
||||
}
|
||||
@ -266,19 +267,19 @@ class EncryptionUtilTest {
|
||||
@Test
|
||||
void testNonceIncorrect() throws Exception {
|
||||
byte[] expected = {1, 2, 3, 4};
|
||||
val serverKey = EncryptionUtil.generateKeyPair();
|
||||
KeyPair serverKey = EncryptionUtil.generateKeyPair();
|
||||
|
||||
// flipped first character
|
||||
val encryptedNonce = encrypt(serverKey.getPublic(), new byte[]{0, 2, 3, 4});
|
||||
byte[] 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};
|
||||
val serverKey = EncryptionUtil.generateKeyPair();
|
||||
KeyPair serverKey = EncryptionUtil.generateKeyPair();
|
||||
// generate a new keypair that is different
|
||||
val encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
|
||||
byte[] encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
|
||||
|
||||
assertThrows(GeneralSecurityException.class,
|
||||
() -> EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce)
|
||||
@ -288,7 +289,7 @@ class EncryptionUtilTest {
|
||||
@Test
|
||||
void testNonceIncorrectEmpty() {
|
||||
byte[] expected = {1, 2, 3, 4};
|
||||
val serverKey = EncryptionUtil.generateKeyPair();
|
||||
KeyPair serverKey = EncryptionUtil.generateKeyPair();
|
||||
byte[] encryptedNonce = {};
|
||||
|
||||
assertThrows(GeneralSecurityException.class,
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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 {
|
||||
val keyUrl = Resources.getResource(resourceName);
|
||||
val encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
|
||||
URL keyUrl = Resources.getResource(resourceName);
|
||||
String encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
|
||||
|
||||
return new Gson().fromJson(encodedSignature, SignatureTestData.class);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -26,7 +26,6 @@
|
||||
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;
|
||||
|
||||
@ -36,7 +35,7 @@ class DelayedAuthHookTest {
|
||||
|
||||
@Test
|
||||
void createNewReflectiveInstance() throws ReflectiveOperationException {
|
||||
val authHook = new DelayedAuthHook(null);
|
||||
DelayedAuthHook authHook = new DelayedAuthHook(null);
|
||||
assertNotNull(authHook.newInstance(DummyHook.class));
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 games647 and contributors
|
||||
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
|
||||
@ -40,6 +40,10 @@
|
||||
<artifactId>fastlogin.bungee</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<!--Represents the main plugin-->
|
||||
<name>FastLoginBungee</name>
|
||||
|
||||
@ -47,20 +51,12 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.6.0</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>
|
||||
@ -82,6 +78,7 @@
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/MANIFEST.MF</exclude>
|
||||
<exclude>**/module-info</exclude>
|
||||
<exclude>**/module-info.class</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
@ -120,13 +117,33 @@
|
||||
<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.19-R0.1-SNAPSHOT</version>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<!-- Use our own newer api version -->
|
||||
<exclusions>
|
||||
@ -135,13 +152,14 @@
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>mysql</groupId>
|
||||
<groupId>com.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>
|
||||
@ -150,6 +168,11 @@
|
||||
<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>
|
||||
@ -158,6 +181,10 @@
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -54,9 +54,15 @@ public class BungeeLoginSource implements LoginSource {
|
||||
preLoginEvent.setCancelled(true);
|
||||
|
||||
if (message == null) {
|
||||
preLoginEvent.setCancelReason(new ComponentBuilder("Kicked").color(ChatColor.WHITE).create());
|
||||
preLoginEvent.setReason(
|
||||
TextComponent.fromArray(
|
||||
new ComponentBuilder("Kicked").color(ChatColor.WHITE).create()
|
||||
));
|
||||
} else {
|
||||
preLoginEvent.setCancelReason(TextComponent.fromLegacyText(message));
|
||||
preLoginEvent.setReason(
|
||||
TextComponent.fromArray(
|
||||
TextComponent.fromLegacyText(message)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +78,7 @@ public class BungeeLoginSource implements LoginSource {
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + '{'
|
||||
+ "connection=" + connection
|
||||
+ '}';
|
||||
+ "connection=" + connection
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -28,7 +28,6 @@ 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;
|
||||
@ -38,6 +37,7 @@ 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.getAntiBot());
|
||||
Listener connectListener = new ConnectListener(this, core.getAntiBotService());
|
||||
pluginManager.registerListener(this, connectListener);
|
||||
pluginManager.registerListener(this, new PluginMessageListener(this));
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -71,25 +71,43 @@ 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 setHandle = null;
|
||||
MethodHandle uniqueIdHandle = null;
|
||||
MethodHandle rewriterHandle = null;
|
||||
try {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
// test for implementation class availability
|
||||
Class.forName("net.md_5.bungee.connection.InitialHandler");
|
||||
|
||||
Field uuidField = InitialHandler.class.getDeclaredField(UUID_FIELD_NAME);
|
||||
uuidField.setAccessible(true);
|
||||
setHandle = lookup.unreflectSetter(uuidField);
|
||||
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"
|
||||
);
|
||||
}
|
||||
} catch (ReflectiveOperationException reflectiveOperationException) {
|
||||
Logger logger = LoggerFactory.getLogger(ConnectListener.class);
|
||||
logger.error(
|
||||
"Cannot find Bungee initial handler; Disabling premium UUID and skin won't work.",
|
||||
"Cannot find Bungee UUID field implementation; Disabling premium UUID and skin won't work.",
|
||||
reflectiveOperationException
|
||||
);
|
||||
}
|
||||
|
||||
UNIQUE_ID_SETTER = setHandle;
|
||||
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);
|
||||
}
|
||||
|
||||
private final FastLoginBungee plugin;
|
||||
@ -179,6 +197,12 @@ 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) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -131,7 +131,7 @@ public class PluginMessageListener implements Listener {
|
||||
loginSession.setRegistered(true);
|
||||
|
||||
if (!loginSession.isAlreadySaved()) {
|
||||
playerProfile.setPremium(true);
|
||||
playerProfile.setOnlinemodePreferred(true);
|
||||
plugin.getCore().getStorage().save(playerProfile);
|
||||
loginSession.setAlreadySaved(true);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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().getPendingLogin().put(ip + username, new Object());
|
||||
plugin.getCore().addLoginAttempt(ip, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -64,29 +64,34 @@ public class AsyncToggleMessage implements Runnable {
|
||||
private void turnOffPremium() {
|
||||
StoredProfile playerProfile = core.getStorage().loadProfile(targetPlayer);
|
||||
//existing player is already cracked
|
||||
if (playerProfile.isSaved() && !playerProfile.isPremium()) {
|
||||
if (playerProfile.isExistingPlayer() && !playerProfile.isOnlinemodePreferred()) {
|
||||
sendMessage("not-premium");
|
||||
return;
|
||||
}
|
||||
|
||||
playerProfile.setPremium(false);
|
||||
playerProfile.setOnlinemodePreferred(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));
|
||||
sendMessage("remove-premium");
|
||||
|
||||
if (isPlayerSender && core.getConfig().getBoolean("kick-toggle", true)) {
|
||||
sender.disconnect(TextComponent.fromLegacyText(core.getMessage("remove-premium")));
|
||||
} else {
|
||||
sendMessage("remove-premium");
|
||||
}
|
||||
}
|
||||
|
||||
private void activatePremium() {
|
||||
StoredProfile playerProfile = core.getStorage().loadProfile(targetPlayer);
|
||||
if (playerProfile.isPremium()) {
|
||||
if (playerProfile.isOnlinemodePreferred()) {
|
||||
sendMessage("already-exists");
|
||||
return;
|
||||
}
|
||||
|
||||
playerProfile.setPremium(true);
|
||||
playerProfile.setOnlinemodePreferred(true);
|
||||
core.getStorage().save(playerProfile);
|
||||
PremiumToggleReason reason = (!isPlayerSender || !sender.getName().equalsIgnoreCase(playerProfile.getName()))
|
||||
? PremiumToggleReason.COMMAND_OTHER : PremiumToggleReason.COMMAND_SELF;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -11,8 +11,6 @@ author: games647, https://github.com/games647/FastLogin/graphs/contributors
|
||||
softDepends:
|
||||
# BungeeCord auth plugins
|
||||
- BungeeAuth
|
||||
- BungeeCordAuthenticatorBungee
|
||||
- SodionAuth
|
||||
# Bedrock Player Bridge
|
||||
- Geyser-BungeeCord
|
||||
- floodgate
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 games647 and contributors
|
||||
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
|
||||
@ -29,35 +29,6 @@
|
||||
<!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
|
||||
@ -227,7 +198,5 @@
|
||||
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
|
||||
<property name="checkFormat" value="$1"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
97
core/pom.xml
97
core/pom.xml
@ -4,7 +4,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 games647 and contributors
|
||||
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
|
||||
@ -39,6 +39,11 @@
|
||||
<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>
|
||||
@ -55,7 +60,7 @@
|
||||
</repository>
|
||||
<!-- Floodgate -->
|
||||
<repository>
|
||||
<id>opencollab-snapshot</id>
|
||||
<id>opencollab</id>
|
||||
<url>https://repo.opencollab.dev/maven-snapshots/</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
@ -68,7 +73,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
@ -80,6 +85,39 @@
|
||||
</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 -->
|
||||
|
||||
@ -102,14 +140,21 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>2.0.11</version>
|
||||
<version>2.0.17</version>
|
||||
</dependency>
|
||||
|
||||
<!-- snakeyaml is present in Bungee, Spigot, Cauldron, so we could use this independent implementation -->
|
||||
<!-- snakeyaml is present in Bungee, Spigot, so we could use this independent implementation -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>1.19-R0.1-SNAPSHOT</version>
|
||||
<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>
|
||||
</dependency>
|
||||
|
||||
<!--Floodgate for Xbox Live Authentication-->
|
||||
@ -158,46 +203,10 @@
|
||||
<dependency>
|
||||
<groupId>com.github.games647</groupId>
|
||||
<artifactId>craftapi</artifactId>
|
||||
<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.1</version>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Database driver included in Spigot -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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(int expireAfterWrite, int maxSize) {
|
||||
public static <K, V> ConcurrentMap<K, V> buildCache(Duration expireAfterWrite, int maxSize) {
|
||||
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
|
||||
|
||||
if (expireAfterWrite > 0) {
|
||||
builder.expireAfterWrite(expireAfterWrite, TimeUnit.MINUTES);
|
||||
if (expireAfterWrite != null) {
|
||||
builder.expireAfterWrite(expireAfterWrite);
|
||||
}
|
||||
|
||||
if (maxSize > 0) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -27,10 +27,9 @@ 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;
|
||||
|
||||
@ -44,38 +43,12 @@ import java.util.Optional;
|
||||
*/
|
||||
public class ProxyAgnosticMojangResolver extends MojangResolver {
|
||||
|
||||
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";
|
||||
|
||||
public ProxyAgnosticMojangResolver(Options options) {
|
||||
super(options);
|
||||
}
|
||||
@Override
|
||||
public Optional<Verification> hasJoined(String username, String serverHash, InetAddress hostIp)
|
||||
throws IOException {
|
||||
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);
|
||||
return super.hasJoined(username, serverHash, null);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -34,8 +34,8 @@ public interface PasswordGenerator<P> {
|
||||
|
||||
/**
|
||||
* Generate a password for a non-registered player
|
||||
* @param player
|
||||
* @return daw
|
||||
* @param player player representation
|
||||
* @return generated password
|
||||
*/
|
||||
String getRandomPassword(P player);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -63,7 +63,7 @@ public class LoginActionMessage implements ChannelMessage {
|
||||
|
||||
@Override
|
||||
public void readFrom(ByteArrayDataInput input) {
|
||||
this.type = Type.values()[input.readInt()];
|
||||
this.type = Type.values()[input.readByte()];
|
||||
|
||||
this.playerName = input.readUTF();
|
||||
|
||||
@ -75,7 +75,7 @@ public class LoginActionMessage implements ChannelMessage {
|
||||
|
||||
@Override
|
||||
public void writeTo(ByteArrayDataOutput output) {
|
||||
output.writeInt(type.ordinal());
|
||||
output.writeByte(type.ordinal());
|
||||
|
||||
//Data is sent through a random player. We have to tell the Bukkit version of this plugin the target
|
||||
output.writeUTF(playerName);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -23,36 +23,22 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.core;
|
||||
package com.github.games647.fastlogin.core.scheduler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public abstract class AbstractAsyncScheduler {
|
||||
|
||||
private static final int MAX_CAPACITY = 1024;
|
||||
protected final Logger logger;
|
||||
protected final Executor processingPool;
|
||||
protected final AtomicInteger currentlyRunning = new AtomicInteger();
|
||||
|
||||
//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) {
|
||||
public AbstractAsyncScheduler(Logger logger, Executor processingPool) {
|
||||
this.logger = logger;
|
||||
this.processingPool = processingPool;
|
||||
}
|
||||
@ -64,7 +50,25 @@ public class AsyncScheduler {
|
||||
});
|
||||
}
|
||||
|
||||
private void process(Runnable task) {
|
||||
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) {
|
||||
currentlyRunning.incrementAndGet();
|
||||
try {
|
||||
task.run();
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -26,6 +26,7 @@
|
||||
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;
|
||||
@ -36,7 +37,6 @@ import com.github.games647.fastlogin.core.antibot.TickingRateLimiter;
|
||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
|
||||
import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
|
||||
import com.github.games647.fastlogin.core.storage.PostgreSQLStorage;
|
||||
import com.github.games647.fastlogin.core.storage.MySQLStorage;
|
||||
import com.github.games647.fastlogin.core.storage.SQLStorage;
|
||||
import com.github.games647.fastlogin.core.storage.SQLiteStorage;
|
||||
@ -49,13 +49,12 @@ 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;
|
||||
@ -79,7 +78,10 @@ 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(5, -1);
|
||||
private final ConcurrentMap<String, Object> pendingLogin = CommonUtil.buildCache(
|
||||
Duration.ofMinutes(5), -1
|
||||
);
|
||||
|
||||
private final Collection<UUID> pendingConfirms = new HashSet<>();
|
||||
private final T plugin;
|
||||
|
||||
@ -118,30 +120,35 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the resolver based on the config parameter
|
||||
this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false)
|
||||
? new ProxyAgnosticMojangResolver() : new MojangResolver();
|
||||
Options resolverOptions = new Options();
|
||||
resolverOptions.setMaxNameRequests(config.getInt("mojang-request-limit", 600));
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
}
|
||||
if (!proxies.isEmpty()) {
|
||||
resolverOptions.setProxySelector(new RotatingProxySelector(proxies));
|
||||
}
|
||||
|
||||
resolver.setMaxNameRequests(config.getInt("mojang-request-limit"));
|
||||
resolver.setProxySelector(new RotatingProxySelector(proxies));
|
||||
resolver.setOutgoingAddresses(addresses);
|
||||
// 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"));
|
||||
}
|
||||
|
||||
private AntiBotService createAntiBotService(Configuration botSection) {
|
||||
@ -231,24 +238,6 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
|
||||
if (type.contains("sqlite")) {
|
||||
storage = new SQLiteStorage(plugin, database, databaseConfig);
|
||||
} else if (type.contains("postgresql")) {
|
||||
String host = config.get("host", "");
|
||||
int port = config.get("port", 3306);
|
||||
boolean useSSL = config.get("useSSL", false);
|
||||
|
||||
if (useSSL) {
|
||||
boolean publicKeyRetrieval = config.getBoolean("allowPublicKeyRetrieval", false);
|
||||
String rsaPublicKeyFile = config.getString("ServerRSAPublicKeyFile");
|
||||
String sslMode = config.getString("sslMode", "Required");
|
||||
|
||||
databaseConfig.addDataSourceProperty("allowPublicKeyRetrieval", publicKeyRetrieval);
|
||||
databaseConfig.addDataSourceProperty("serverRSAPublicKeyFile", rsaPublicKeyFile);
|
||||
databaseConfig.addDataSourceProperty("sslMode", sslMode);
|
||||
}
|
||||
|
||||
databaseConfig.setUsername(config.get("username", ""));
|
||||
databaseConfig.setPassword(config.getString("password"));
|
||||
storage = new PostgreSQLStorage(plugin, type, host, port, database, databaseConfig, useSSL);
|
||||
} else {
|
||||
String host = config.get("host", "");
|
||||
int port = config.get("port", 3306);
|
||||
@ -291,8 +280,16 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
}
|
||||
|
||||
public ConcurrentMap<String, Object> getPendingLogin() {
|
||||
return pendingLogin;
|
||||
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 Collection<UUID> getPendingConfirms() {
|
||||
@ -303,7 +300,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
return authPlugin;
|
||||
}
|
||||
|
||||
public AntiBotService getAntiBot() {
|
||||
public AntiBotService getAntiBotService() {
|
||||
return antiBot;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -62,9 +62,9 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
|
||||
this.username = getName(player);
|
||||
|
||||
//load values from config.yml
|
||||
autoLoginFloodgate = core.getConfig().getString("autoLoginFloodgate").toLowerCase(Locale.ROOT);
|
||||
autoRegisterFloodgate = core.getConfig().getString("autoRegisterFloodgate").toLowerCase(Locale.ROOT);
|
||||
allowNameConflict = core.getConfig().getString("allowFloodgateNameConflict").toLowerCase(Locale.ROOT);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +82,7 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
|
||||
|
||||
profile = core.getStorage().loadProfile(username);
|
||||
|
||||
if (profile.isSaved()) {
|
||||
if (profile.isExistingPlayer()) {
|
||||
if (profile.isFloodgateMigrated()) {
|
||||
if (profile.getFloodgate() == FloodgateState.TRUE && isLinked) {
|
||||
core.getPlugin().getLog()
|
||||
@ -121,7 +121,7 @@ public abstract class FloodgateManagement<P extends C, C, L extends LoginSession
|
||||
//maybe Bungee without auth plugin
|
||||
if (authPlugin == null) {
|
||||
if (profile != null) {
|
||||
isRegistered = profile.isPremium();
|
||||
isRegistered = profile.isOnlinemodePreferred();
|
||||
} else {
|
||||
isRegistered = false;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -47,7 +47,7 @@ public enum FloodgateState {
|
||||
*/
|
||||
NOT_MIGRATED(3);
|
||||
|
||||
private int value;
|
||||
private final int value;
|
||||
|
||||
FloodgateState(int value) {
|
||||
this.value = value;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -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.setPremium(true);
|
||||
playerProfile.setOnlinemodePreferred(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.setPremium(false);
|
||||
playerProfile.setOnlinemodePreferred(false);
|
||||
storage.save(playerProfile);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -48,8 +48,6 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
}
|
||||
|
||||
public void onLogin(String username, S source) {
|
||||
core.getPlugin().getLog().info("Handling player {}", username);
|
||||
|
||||
//check if the player is connecting through Bedrock Edition
|
||||
if (bedrockService != null && bedrockService.isBedrockConnection(username)) {
|
||||
//perform Bedrock specific checks and skip Java checks if no longer needed
|
||||
@ -59,7 +57,6 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -74,62 +71,65 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
} else {
|
||||
profile.setFloodgate(FloodgateState.FALSE);
|
||||
core.getPlugin().getLog().info(
|
||||
"Player {} will be migrated to the v2 database schema as a JAVA user", username);
|
||||
"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);
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (profile.isExistingPlayer()) {
|
||||
if (profile.isOnlinemodePreferred()) {
|
||||
core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username);
|
||||
requestPremiumLogin(source, profile, username, true);
|
||||
} 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//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"));
|
||||
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) throws Exception {
|
||||
protected boolean isValidUsername(LoginSource source, StoredProfile profile) {
|
||||
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 +139,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkPremiumName(S source, String username, StoredProfile profile) throws Exception {
|
||||
private boolean isUsernameAvailable(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,7 +149,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkNameChange(S source, String username, Profile profile) {
|
||||
private boolean isNameChanged(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());
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -31,7 +31,7 @@ public interface LoginSource {
|
||||
|
||||
void enableOnlinemode() throws Exception;
|
||||
|
||||
void kick(String message) throws Exception;
|
||||
void kick(String message);
|
||||
|
||||
InetSocketAddress getAddress();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -25,8 +25,8 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.core.shared;
|
||||
|
||||
import com.github.games647.fastlogin.core.AsyncScheduler;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.BedrockService;
|
||||
import com.github.games647.fastlogin.core.scheduler.AsyncScheduler;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
@ -30,7 +30,7 @@ import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
|
||||
/**
|
||||
* This event fires if the plugin performs an auto login on the platform where the login plugin is
|
||||
*
|
||||
* <p>
|
||||
* {@snippet :
|
||||
* @EventHandler()
|
||||
* public void onPlayerLogin(FastLoginAutoLoginEvent loginEvent) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2023 games647 and contributors
|
||||
* 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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user