Compare commits

..

1 Commits

66 changed files with 277 additions and 1585 deletions

View File

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

View File

@@ -1,22 +0,0 @@
---
name: Enhancement request
about: New feature or change request
title: ''
labels: 'enhancement'
assignees: ''
---
[//]: # (Lines in this format are considered as comments and will not be displayed.)
### Is your feature request related to a problem? Please describe.
[//]: # (A clear and concise description of what the problem is. Ex. I'm always frustrated when [...])
### Describe the solution you'd like
[//]: # (A clear and concise description of what you want to happen.)
### Describe alternatives you've considered
[//]: # (A clear and concise description of any alternative solutions or features you've considered.)
### Additional context
[//]: # (Add any other context or screenshots about the feature request here.)

View File

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

View File

@@ -1,8 +0,0 @@
[//]: # (Lines in this format are considered as comments and will not be displayed.)
[//]: # (If your work is in progress, please consider making a draft pull request.)
### Summary of your change
[//]: # (Example: motiviation, enhancement)
### Related issue
[//]: # (Reference it using '#NUMBER'. Ex: Fixes/Related #...)

View File

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

1
.gitignore vendored
View File

@@ -15,7 +15,6 @@ nb-configuration.xml
# Maven
target/
pom.xml.versionsBackup
# Gradle
.gradle

13
.travis.yml Normal file
View File

@@ -0,0 +1,13 @@
# Use https://travis-ci.org/ for automatic testing
# speed up testing https://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
sudo: false
# This is a java project
language: java
script: mvn test -B
jdk:
- oraclejdk8
- oraclejdk9

View File

@@ -3,7 +3,7 @@
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).
## Features
### Features:
* Detect paid accounts from others
* Automatically login paid accounts (premium)
@@ -20,43 +20,31 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
* Good performance by using async non blocking operations
* Locale messages
* Import the database from similar plugins
## Development builds
Development builds of this project can be acquired at the provided CI (continuous integration) server. It contains the
latest changes from the Source-Code in preparation for the following release. This means they could contain new
features, bug fixes and other changes since the last release.
Nevertheless builds are only tested using a small set of automated and a few manual tests. Therefore they **could**
contain new bugs and are likely to be less stable than released versions.
https://ci.codemc.org/job/Games647/job/FastLogin/changes
* Free
* Open source
***
## Commands
### Commands:
/premium [player] Label the invoker or the argument as paid account
/cracked [player] Label the invoker or the argument as cracked account
## Permissions
### Permissions:
fastlogin.bukkit.command.premium
fastlogin.bukkit.command.cracked
fastlogin.command.premium.other
fastlogin.command.cracked.other
fastlogin.command.import
## Requirements
* Plugin:
* [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or
* [ProtocolSupport](https://www.spigotmc.org/resources/protocolsupport.7201/)
* [Spigot](https://www.spigotmc.org) 1.7.10+
### Requirements:
* Plugin: [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or
[ProtocolSupport](https://www.spigotmc.org/resources/protocolsupport.7201/)
* [Spigot](https://www.spigotmc.org) 1.7+
* Java 8+
* Run Spigot and/or BungeeCord/Waterfall in offline mode (see server.properties or config.yml)
* An auth plugin. Supported plugins
### Bukkit/Spigot/Paper
#### Bukkit/Spigot/Paper
* [AuthMe (5.X)](https://dev.bukkit.org/bukkit-plugins/authme-reloaded/)
* [xAuth](https://dev.bukkit.org/bukkit-plugins/xauth/)
@@ -66,36 +54,28 @@ https://ci.codemc.org/job/Games647/job/FastLogin/changes
* [LoginSecurity](https://dev.bukkit.org/bukkit-plugins/loginsecurity/)
* [UltraAuth](https://dev.bukkit.org/bukkit-plugins/ultraauth-aa/)
### BungeeCord/Waterfall
#### BungeeCord/Waterfall
* [BungeeAuth](https://www.spigotmc.org/resources/bungeeauth.493/)
## Network requests
This plugin performs network requests to:
* https://api.mojang.com - retrieving uuid data to decide if we should activate premium login
* https://sessionserver.mojang.com - verify if the player is the owner of that account
***
## How to install
### How to install
### Bukkit/Spigot/Paper
#### Bukkit/Spigot/Paper
1. Download and install ProtocolLib/ProtocolSupport
2. Download and install FastLogin (or FastLoginBukkit for newer versions)
1. Download and install ProtocolLib
2. Download and install FastLogin
3. Set your server in offline mode by setting the value onlinemode in your server.properties to false
### BungeeCord/Waterfall
#### BungeeCord/Waterfall
1. Activate BungeeCord in the Spigot configuration
2. Restart your server
3. Now there is proxy-whitelist file in the FastLogin folder
Put your stats id from the BungeeCord config into this file
4. Activate ipForward in your BungeeCord config
5. Download and Install FastLogin (or FastLoginBungee in newer versions) on BungeeCord AND Spigot
(on the servers where your login plugin is or where player should be able to execute the commands of FastLogin)
5. Download and Install FastLogin on BungeeCord AND Spigot (on the servers where your login plugin is)
6. Check your database settings in the config of FastLogin on BungeeCord
7. Set your proxy (BungeeCord) in offline mode by setting the value onlinemode in your config.yml to false
8. You should *always* firewall your Spigot server that it's only accessible through BungeeCord

View File

@@ -1,11 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.games647</groupId>
<artifactId>fastlogin</artifactId>
<version>1.11-SNAPSHOT</version>
<version>1.11</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -20,7 +20,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<version>3.1.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>false</shadedArtifactAttached>
@@ -56,52 +56,44 @@
</build>
<repositories>
<!-- Bukkit-Server-API -->
<!--Bukkit-Server-API -->
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
<!-- Disable snapshot release policy to speed up, when finding a artifact -->
<releases>
<enabled>false</enabled>
</releases>
</repository>
<!-- ProtocolLib -->
<!--LoginSecurity-->
<repository>
<id>lenis0012-repo</id>
<url>http://ci.lenis0012.com/plugin/repository/everything/</url>
</repository>
<!--ProtocolLib-->
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/nexus/repository/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
</repository>
<!-- AuthMe Reloaded, xAuth and LoginSecurity -->
<!--AuthMe Reloaded and xAuth -->
<repository>
<id>codemc-releases</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<!-- GitHub automatic maven builds -->
<!--GitHub automatic maven builds-->
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<!-- PlaceholderAPI -->
<!--PlaceholderAPI -->
<repository>
<id>placeholderapi</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>http://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
<!--Common plugin component-->
<dependency>
<groupId>com.github.games647</groupId>
<artifactId>fastlogin.core</artifactId>
@@ -120,24 +112,22 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>4.5.0</version>
<version>4.3.0</version>
<scope>provided</scope>
</dependency>
<!--Changing onlinemode on login process-->
<dependency>
<groupId>com.github.ProtocolSupport</groupId>
<artifactId>ProtocolSupport</artifactId>
<!--4.29.dev after commit about API improvements-->
<version>3a80c661fe</version>
<!--4.25.dev-->
<version>a4f060dc46</version>
<scope>provided</scope>
</dependency>
<!--Provide premium placeholders-->
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.10.4</version>
<version>2.8.4</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
@@ -166,7 +156,7 @@
<dependency>
<groupId>com.lenis0012.bukkit</groupId>
<artifactId>loginsecurity</artifactId>
<version>3.0.1</version>
<version>2.1.7</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>

View File

@@ -13,47 +13,21 @@ import java.util.Optional;
*/
public class BukkitLoginSession extends LoginSession {
private static final byte[] EMPTY_ARRAY = {};
private final String serverId;
private final byte[] verifyToken;
private SkinProperty skinProperty;
private boolean verified;
private SkinProperty skinProperty;
public BukkitLoginSession(String username, String serverId, byte[] verifyToken, boolean registered
, StoredProfile profile) {
public BukkitLoginSession(String username, boolean registered, StoredProfile profile) {
super(username, registered, profile);
this.serverId = serverId;
this.verifyToken = verifyToken.clone();
}
//available for BungeeCord
public BukkitLoginSession(String username, boolean registered) {
this(username, "", EMPTY_ARRAY, registered, null);
this(username, registered, null);
}
//cracked player
public BukkitLoginSession(String username, StoredProfile profile) {
this(username, "", EMPTY_ARRAY, false, profile);
}
//ProtocolSupport
public BukkitLoginSession(String username, boolean registered, StoredProfile profile) {
this(username, "", EMPTY_ARRAY, registered, profile);
}
/**
* Gets the verify token the server sent to the client.
*
* Empty if it's a BungeeCord connection
*
* @return the verify token from the server
*/
public synchronized byte[] getVerifyToken() {
return verifyToken.clone();
this(username, false, profile);
}
/**

View File

@@ -1,116 +0,0 @@
package com.github.games647.fastlogin.bukkit;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* Encryption and decryption minecraft util for connection between servers
* and paid Minecraft account clients.
*
* @see net.minecraft.server.MinecraftEncryption
*/
public class EncryptionUtil {
public static final int VERIFY_TOKEN_LENGTH = 4;
public static final String KEY_PAIR_ALGORITHM = "RSA";
private EncryptionUtil() {
//utility
}
/**
* Generate a RSA key pair
*
* @return The RSA key pair.
*/
public static KeyPair generateKeyPair() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
keyPairGenerator.initialize(1_024);
return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException nosuchalgorithmexception) {
//Should be existing in every vm
throw new ExceptionInInitializerError(nosuchalgorithmexception);
}
}
/**
* Generate a random token. This is used to verify that we are communicating with the same player
* in a login session.
*
* @param random random generator
* @return an error with 4 bytes long
*/
public static byte[] generateVerifyToken(Random random) {
byte[] token = new byte[VERIFY_TOKEN_LENGTH];
random.nextBytes(token);
return token;
}
/**
* Generate the server id based on client and server data.
*
* @param sessionId session for the current login attempt
* @param sharedSecret shared secret between the client and the server
* @param publicKey public key of the server
* @return the server id formatted as a hexadecimal string.
*/
public static String getServerIdHashString(String sessionId, Key sharedSecret, PublicKey publicKey) {
try {
byte[] serverHash = getServerIdHash(sessionId, sharedSecret, publicKey);
return (new BigInteger(serverHash)).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
/**
* Decrypts the content and extracts the key spec.
*
* @param cipher decryption cipher initialized with the private key
* @param sharedKey the encrypted shared key
* @return shared secret key
* @throws GeneralSecurityException if it fails to decrypt the data
*/
public static SecretKey decryptSharedKey(Cipher cipher, byte[] sharedKey) throws GeneralSecurityException {
return new SecretKeySpec(decrypt(cipher, sharedKey), "AES");
}
/**
* Decrypted the given data using the cipher.
*
* @param cipher decryption cypher initialized with the private key
* @param data the encrypted data
* @return clear text data
* @throws GeneralSecurityException if it fails to decrypt the data
*/
public static byte[] decrypt(Cipher cipher, byte[] data) throws GeneralSecurityException {
return cipher.doFinal(data);
}
private static byte[] getServerIdHash(String sessionId, Key sharedSecret, PublicKey publicKey)
throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(sessionId.getBytes(StandardCharsets.ISO_8859_1));
digest.update(sharedSecret.getEncoded());
digest.update(publicKey.getEncoded());
return digest.digest();
}
}

View File

@@ -1,18 +1,14 @@
package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.bukkit.command.CrackedCommand;
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
import com.github.games647.fastlogin.bukkit.commands.CrackedCommand;
import com.github.games647.fastlogin.bukkit.commands.PremiumCommand;
import com.github.games647.fastlogin.bukkit.listener.BungeeListener;
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener;
import com.github.games647.fastlogin.bukkit.listener.protocollib.SkinApplyListener;
import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener;
import com.github.games647.fastlogin.bukkit.task.DelayedAuthHook;
import com.github.games647.fastlogin.bukkit.tasks.DelayedAuthHook;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.messages.ChannelMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.google.common.io.ByteArrayDataOutput;
@@ -26,22 +22,18 @@ import java.util.concurrent.ConcurrentMap;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.messaging.PluginMessageRecipient;
import org.slf4j.Logger;
import static com.github.games647.fastlogin.core.message.ChangePremiumMessage.CHANGE_CHANNEL;
import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL;
/**
* This plugin checks if a player has a paid account and if so tries to skip offline mode authentication.
*/
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 = new ConcurrentHashMap<>();
private final Logger logger = CommonUtil.createLoggerFromJDK(getLogger());
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
@@ -69,26 +61,10 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
}
PluginManager pluginManager = getServer().getPluginManager();
Plugin protocolLib = pluginManager.getPlugin("ProtocolLib");
if (protocolLib != null && !protocolLib.isEnabled()) {
logger.warn("Dependency graph issue. ProtocolLib should be loaded first.");
logger.warn(getDescription().getSoftDepend().toString());
logger.warn(getDescription().getDepend().toString());
logger.warn(getDescription().getLoadBefore().toString());
}
if (bungeeCord) {
setServerStarted();
// check for incoming messages from the bungeecord version of this plugin
String forceChannel = new NamespaceKey(getName(), LoginActionMessage.FORCE_CHANNEL).getCombinedName();
getServer().getMessenger().registerIncomingPluginChannel(this, forceChannel, new BungeeListener(this));
// outgoing
String successChannel = new NamespaceKey(getName(), SUCCESS_CHANNEL).getCombinedName();
String changeChannel = new NamespaceKey(getName(), CHANGE_CHANNEL).getCombinedName();
getServer().getMessenger().registerOutgoingPluginChannel(this, successChannel);
getServer().getMessenger().registerOutgoingPluginChannel(this, changeChannel);
//check for incoming messages from the bungeecord version of this plugin
getServer().getMessenger().registerIncomingPluginChannel(this, getName(), new BungeeListener(this));
getServer().getMessenger().registerOutgoingPluginChannel(this, getName());
} else {
if (!core.setupDatabase()) {
setEnabled(false);
@@ -97,11 +73,8 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
pluginManager.registerEvents(new ProtocolSupportListener(this), this);
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
ProtocolLibListener.register(this);
pluginManager.registerEvents(new SkinApplyListener(this), this);
} else {
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
logger.warn("ProtocolSupport have to be installed if you don't use BungeeCord");
}
}
@@ -168,29 +141,13 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
return premiumPlayers.getOrDefault(onlinePlayer, PremiumStatus.UNKNOWN);
}
/**
* Wait before the server is fully started. This is workaround, because connections right on startup are not
* injected by ProtocolLib
*
* @return true if ProtocolLib can now intercept packets
*/
public boolean isServerFullyStarted() {
return serverStarted;
}
public void setServerStarted() {
if (!this.serverStarted) {
this.serverStarted = true;
}
}
public void sendPluginMessage(PluginMessageRecipient player, ChannelMessage message) {
if (player != null) {
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
message.writeTo(dataOutput);
dataOutput.writeUTF(message.getChannelName());
NamespaceKey channel = new NamespaceKey(getName(), message.getChannelName());
player.sendPluginMessage(this, channel.getCombinedName(), dataOutput.toByteArray());
message.writeTo(dataOutput);
player.sendPluginMessage(this, this.getName(), dataOutput.toByteArray());
}
}

View File

@@ -1,15 +1,11 @@
package com.github.games647.fastlogin.bukkit;
import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.PlaceholderHook;
import org.bukkit.entity.Player;
public class PremiumPlaceholder extends PlaceholderExpansion {
private static final String PLACEHOLDER_VARIABLE = "fastlogin_status";
public class PremiumPlaceholder extends PlaceholderHook {
private final FastLoginBukkit plugin;
@@ -17,37 +13,16 @@ public class PremiumPlaceholder extends PlaceholderExpansion {
this.plugin = plugin;
}
public static void register(FastLoginBukkit plugin) {
PremiumPlaceholder placeholderHook = new PremiumPlaceholder(plugin);
PlaceholderAPI.registerPlaceholderHook(PLACEHOLDER_VARIABLE, placeholderHook);
}
@Override
public String onPlaceholderRequest(Player player, String variable) {
if (player != null && PLACEHOLDER_VARIABLE.equals(variable)) {
if (player != null && "fastlogin_status".contains(variable)) {
return plugin.getStatus(player.getUniqueId()).name();
}
return "";
}
@Override
public String getIdentifier() {
return PLACEHOLDER_VARIABLE;
}
@Override
public String getPlugin() {
return plugin.getName();
}
@Override
public String getAuthor() {
return plugin.getDescription().getAuthors().stream().collect(Collectors.joining(", "));
}
@Override
public String getVersion() {
return plugin.getName();
public static void register(FastLoginBukkit plugin) {
PlaceholderAPI.registerPlaceholderHook(plugin, new PremiumPlaceholder(plugin));
}
}

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.command;
package com.github.games647.fastlogin.bukkit.commands;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.StoredProfile;

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.command;
package com.github.games647.fastlogin.bukkit.commands;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.StoredProfile;

View File

@@ -1,8 +1,8 @@
package com.github.games647.fastlogin.bukkit.command;
package com.github.games647.fastlogin.bukkit.commands;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.messages.ChangePremiumMessage;
import com.github.games647.fastlogin.core.messages.ChannelMessage;
import java.util.Optional;

View File

@@ -1,52 +0,0 @@
package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class BukkitFastLoginAutoLoginEvent extends Event implements FastLoginAutoLoginEvent, Cancellable {
private static final HandlerList handlers = new HandlerList();
private final LoginSession session;
private final StoredProfile profile;
private boolean cancelled;
public BukkitFastLoginAutoLoginEvent(LoginSession session, StoredProfile profile) {
super(true);
this.session = session;
this.profile = profile;
}
@Override
public LoginSession getSession() {
return session;
}
@Override
public StoredProfile getProfile() {
return profile;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,47 +0,0 @@
package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class BukkitFastLoginPreLoginEvent extends Event implements FastLoginPreLoginEvent {
private static final HandlerList handlers = new HandlerList();
private final String username;
private final LoginSource source;
private final StoredProfile profile;
public BukkitFastLoginPreLoginEvent(String username, LoginSource source, StoredProfile profile) {
super(true);
this.username = username;
this.source = source;
this.profile = profile;
}
@Override
public String getUsername() {
return username;
}
@Override
public LoginSource getSource() {
return source;
}
@Override
public StoredProfile getProfile() {
return profile;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
@@ -42,11 +42,11 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
@Override
public boolean forceLogin(Player player) {
//skips registration and login
if (AuthMeApi.getInstance().isAuthenticated(player)) {
return false;
}
//skips registration and login
AuthMeApi.getInstance().forceLogin(player);
return true;
}
@@ -58,7 +58,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
@Override
public boolean forceRegister(Player player, String password) {
//this automatically login the player too
//this automatically registers the player too
AuthMeApi.getInstance().forceRegister(player, password);
return true;
}

View File

@@ -1,6 +1,5 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.comphenix.protocol.reflect.FieldUtils;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
@@ -14,6 +13,7 @@ import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.commons.lang.reflect.FieldUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
@@ -11,7 +11,7 @@ import com.lenis0012.bukkit.loginsecurity.session.action.RegisterAction;
import org.bukkit.entity.Player;
/**
* GitHub: https://github.com/lenis0012/LoginSecurity-2
* GitHub: https://github.com/lenis0012/LoginSecurity-2
* <p>
* Project page:
* <p>
@@ -30,8 +30,8 @@ public class LoginSecurityHook implements AuthPlugin<Player> {
@Override
public boolean forceLogin(Player player) {
PlayerSession session = LoginSecurity.getSessionManager().getPlayerSession(player);
return session.isAuthorized()
|| session.performAction(new LoginAction(AuthService.PLUGIN, plugin)).isSuccess();
return session.isAuthorized() || session.performAction(new LoginAction(AuthService.PLUGIN, plugin)).isSuccess();
}
@Override

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.hook;
package com.github.games647.fastlogin.bukkit.hooks;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;

View File

@@ -2,11 +2,11 @@ package com.github.games647.fastlogin.bukkit.listener;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
import com.github.games647.fastlogin.bukkit.tasks.ForceLoginTask;
import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage.Type;
import com.github.games647.fastlogin.core.messages.LoginActionMessage;
import com.github.games647.fastlogin.core.messages.LoginActionMessage.Type;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
@@ -46,7 +46,16 @@ public class BungeeListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals(plugin.getName())) {
return;
}
ByteArrayDataInput dataInput = ByteStreams.newDataInput(message);
String subChannel = dataInput.readUTF();
if (!"LoginAction".equals(subChannel)) {
plugin.getLog().info("Unknown sub channel {}", subChannel);
return;
}
LoginActionMessage loginMessage = new LoginActionMessage();
loginMessage.readFrom(dataInput);
@@ -61,8 +70,6 @@ public class BungeeListener implements PluginMessageListener {
//fail if target player is blacklisted because already authenticated or wrong bungeecord id
if (checkedPlayer.hasMetadata(plugin.getName())) {
plugin.getLog().warn("Received message {} from a blacklisted player {}", loginMessage, checkedPlayer);
} else {
//fail if BungeeCord support is disabled (id = null)
UUID sourceId = loginMessage.getProxyId();
if (proxyIds.contains(sourceId)) {
@@ -70,6 +77,8 @@ public class BungeeListener implements PluginMessageListener {
} else {
plugin.getLog().warn("Received proxy id: {} that doesn't exist in the proxy whitelist file", sourceId);
}
} else {
plugin.getLog().warn("Received message {} from a blacklisted player {}", loginMessage, checkedPlayer);
}
}
@@ -80,12 +89,16 @@ public class BungeeListener implements PluginMessageListener {
InetSocketAddress address = player.getAddress();
String id = '/' + address.getAddress().getHostAddress() + ':' + address.getPort();
if (type == Type.LOGIN) {
plugin.getPremiumPlayers().put(player.getUniqueId(), PremiumStatus.PREMIUM);
BukkitLoginSession playerSession = new BukkitLoginSession(playerName, true);
playerSession.setVerified(true);
plugin.getLoginSessions().put(id, playerSession);
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, new ForceLoginTask(plugin.getCore(), player), 10L);
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, new ForceLoginTask(plugin.getCore(), player), 20L);
} else if (type == Type.REGISTER) {
plugin.getPremiumPlayers().put(player.getUniqueId(), PremiumStatus.PREMIUM);
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> {
AuthPlugin<Player> authPlugin = plugin.getCore().getAuthPluginHook();
try {
@@ -99,9 +112,8 @@ public class BungeeListener implements PluginMessageListener {
} catch (Exception ex) {
plugin.getLog().error("Failed to query isRegistered for player: {}", player, ex);
}
}, 10L);
}, 20L);
} else if (type == Type.CRACKED) {
//we don't start a force login task here so update it manually
plugin.getPremiumPlayers().put(player.getUniqueId(), PremiumStatus.CRACKED);
}
}

View File

@@ -1,16 +1,13 @@
package com.github.games647.fastlogin.bukkit.listener;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
import com.github.games647.fastlogin.bukkit.tasks.ForceLoginTask;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
import org.bukkit.event.player.PlayerQuitEvent;
/**
@@ -27,18 +24,10 @@ public class ConnectionListener implements Listener {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
if (loginEvent.getResult() == Result.ALLOWED && !plugin.isServerFullyStarted()) {
loginEvent.disallow(Result.KICK_OTHER, plugin.getCore().getMessage("not-started"));
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
Player player = joinEvent.getPlayer();
removeBlacklistStatus(player);
if (!plugin.isBungeeEnabled()) {
//Wait before auth plugin and we received a message from BungeeCord initializes the player
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player);
@@ -49,13 +38,9 @@ public class ConnectionListener implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent quitEvent) {
Player player = quitEvent.getPlayer();
removeBlacklistStatus(player);
player.removeMetadata(plugin.getName(), plugin);
plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
plugin.getPremiumPlayers().remove(player.getUniqueId());
}
private void removeBlacklistStatus(Player player) {
player.removeMetadata(plugin.getName(), plugin);
}
}

View File

@@ -1,89 +0,0 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketEvent;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import java.security.PublicKey;
import java.util.Random;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource>
implements Runnable {
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
private final PublicKey publicKey;
private final Random random;
private final Player player;
private final String username;
public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random,
Player player, String username, PublicKey publicKey) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
this.plugin = plugin;
this.packetEvent = packetEvent;
this.publicKey = publicKey;
this.random = random;
this.player = player;
this.username = username;
}
@Override
public void run() {
try {
super.onLogin(username, new ProtocolLibLoginSource(packetEvent, player, random, publicKey));
} finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
}
@Override
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLibLoginSource source, StoredProfile profile) {
BukkitFastLoginPreLoginEvent event = new BukkitFastLoginPreLoginEvent(username, source, profile);
plugin.getServer().getPluginManager().callEvent(event);
return event;
}
//Minecraft server implementation
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
@Override
public void requestPremiumLogin(ProtocolLibLoginSource source, StoredProfile profile
, String username, boolean registered) {
try {
source.setOnlineMode();
} catch (Exception ex) {
plugin.getLog().error("Cannot send encryption packet. Falling back to cracked login for: {}", profile, ex);
return;
}
String ip = player.getAddress().getAddress().getHostAddress();
core.getPendingLogin().put(ip + username, new Object());
String serverId = source.getServerId();
byte[] verify = source.getVerifyToken();
BukkitLoginSession playerSession = new BukkitLoginSession(username, serverId, verify, registered, profile);
plugin.getLoginSessions().put(player.getAddress().toString(), playerSession);
//cancel only if the player has a paid account otherwise login as normal offline player
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
packetEvent.setCancelled(true);
}
}
@Override
public void startCrackedSession(ProtocolLibLoginSource source, StoredProfile profile, String username) {
BukkitLoginSession loginSession = new BukkitLoginSession(username, profile);
plugin.getLoginSessions().put(player.getAddress().toString(), loginSession);
}
}

View File

@@ -1,90 +0,0 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.PacketType;
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.github.games647.fastlogin.bukkit.EncryptionUtil;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import java.security.KeyPair;
import java.security.SecureRandom;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN;
import static com.comphenix.protocol.PacketType.Login.Client.START;
public class ProtocolLibListener extends PacketAdapter {
private static final int WORKER_THREADS = 3;
private final FastLoginBukkit plugin;
//just create a new once on plugin enable. This used for verify token generation
private final SecureRandom random = new SecureRandom();
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
public ProtocolLibListener(FastLoginBukkit plugin) {
//run async in order to not block the server, because we are making api calls to Mojang
super(params()
.plugin(plugin)
.types(START, ENCRYPTION_BEGIN)
.optionAsync());
this.plugin = plugin;
}
public static void register(FastLoginBukkit plugin) {
//they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
ProtocolLibrary.getProtocolManager()
.getAsynchronousManager()
.registerAsyncHandler(new ProtocolLibListener(plugin))
.start(WORKER_THREADS);
}
@Override
public void onPacketReceiving(PacketEvent packetEvent) {
if (packetEvent.isCancelled()
|| plugin.getCore().getAuthPluginHook()== null
|| !plugin.isServerFullyStarted()) {
return;
}
Player sender = packetEvent.getPlayer();
PacketType packetType = packetEvent.getPacketType();
if (packetType == START) {
onLogin(packetEvent, sender);
} else {
onEncryptionBegin(packetEvent, sender);
}
}
private void onEncryptionBegin(PacketEvent packetEvent, Player sender) {
byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0);
packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair);
Bukkit.getScheduler().runTaskAsynchronously(plugin, verifyTask);
}
private void onLogin(PacketEvent packetEvent, Player player) {
//this includes ip:port. Should be unique for an incoming login request with a timeout of 2 minutes
String sessionKey = player.getAddress().toString();
//remove old data every time on a new login in order to keep the session only for one person
plugin.getLoginSessions().remove(sessionKey);
//player.getName() won't work at this state
PacketContainer packet = packetEvent.getPacket();
String username = packet.getGameProfiles().read(0).getName();
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username, keyPair.getPublic());
Bukkit.getScheduler().runTaskAsynchronously(plugin, nameCheckTask);
}
}

View File

@@ -1,100 +0,0 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.github.games647.fastlogin.bukkit.EncryptionUtil;
import com.github.games647.fastlogin.core.shared.LoginSource;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Random;
import org.bukkit.entity.Player;
import static com.comphenix.protocol.PacketType.Login.Server.DISCONNECT;
import static com.comphenix.protocol.PacketType.Login.Server.ENCRYPTION_BEGIN;
public class ProtocolLibLoginSource implements LoginSource {
private final PacketEvent packetEvent;
private final Player player;
private final Random random;
private final PublicKey publicKey;
private final String serverId = "";
private byte[] verifyToken;
public ProtocolLibLoginSource(PacketEvent packetEvent, Player player, Random random, PublicKey publicKey) {
this.packetEvent = packetEvent;
this.player = player;
this.random = random;
this.publicKey = publicKey;
}
@Override
public void setOnlineMode() throws Exception {
verifyToken = EncryptionUtil.generateVerifyToken(random);
/*
* Packet Information: https://wiki.vg/Protocol#Encryption_Request
*
* ServerID="" (String) key=public server key verifyToken=random 4 byte array
*/
PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN);
newPacket.getStrings().write(0, serverId);
newPacket.getSpecificModifier(PublicKey.class).write(0, publicKey);
newPacket.getByteArrays().write(0, verifyToken);
//serverId is a empty string
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket);
}
@Override
public void kick(String message) throws InvocationTargetException {
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
PacketContainer kickPacket = new PacketContainer(DISCONNECT);
kickPacket.getChatComponents().write(0, WrappedChatComponent.fromText(message));
try {
//send kick packet at login state
//the normal event.getPlayer.kickPlayer(String) method does only work at play state
protocolManager.sendServerPacket(player, kickPacket);
} finally {
//tell the server that we want to close the connection
player.kickPlayer("Disconnect");
}
}
@Override
public InetSocketAddress getAddress() {
return packetEvent.getPlayer().getAddress();
}
public String getServerId() {
return serverId;
}
public byte[] getVerifyToken() {
return verifyToken.clone();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + '{' +
"packetEvent=" + packetEvent +
", player=" + player +
", random=" + random +
", serverId='" + serverId + '\'' +
", verifyToken=" + Arrays.toString(verifyToken) +
'}';
}
}

View File

@@ -1,70 +0,0 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.reflect.MethodUtils;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.github.games647.craftapi.model.skin.Textures;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import java.lang.reflect.InvocationTargetException;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
public class SkinApplyListener implements Listener {
private static final Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass();
private static final MethodAccessor GET_PROPERTIES = Accessors.getMethodAccessor(GAME_PROFILE, "getProperties");
private final FastLoginBukkit plugin;
public SkinApplyListener(FastLoginBukkit plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOW)
//run this on the loginEvent to let skins plugins see the skin like in normal Minecraft behaviour
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
if (loginEvent.getResult() != Result.ALLOWED) {
return;
}
Player player = loginEvent.getPlayer();
if (plugin.getConfig().getBoolean("forwardSkin")) {
//go through every session, because player.getAddress is null
//loginEvent.getAddress is just a InetAddress not InetSocketAddress, so not unique enough
for (BukkitLoginSession session : plugin.getLoginSessions().values()) {
if (session.getUsername().equals(player.getName())) {
session.getSkin().ifPresent(skin -> applySkin(player, skin.getValue(), skin.getSignature()));
break;
}
}
}
}
private void applySkin(Player player, String skinData, String signature) {
WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player);
WrappedSignedProperty skin = WrappedSignedProperty.fromValues(Textures.KEY, skinData, signature);
try {
gameProfile.getProperties().put(Textures.KEY, skin);
} catch (ClassCastException castException) {
//Cauldron, MCPC, Thermos, ...
Object map = GET_PROPERTIES.invoke(gameProfile.getHandle());
try {
MethodUtils.invokeMethod(map, "put", new Object[]{Textures.KEY, skin.getHandle()});
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
plugin.getLog().error("Error setting premium skin of: {}", player, ex);
}
}
}
}

View File

@@ -1,234 +0,0 @@
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.server.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.EncryptionUtil;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.util.Arrays;
import java.util.Optional;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import org.bukkit.entity.Player;
import static com.comphenix.protocol.PacketType.Login.Client.START;
import static com.comphenix.protocol.PacketType.Login.Server.DISCONNECT;
public class VerifyResponseTask implements Runnable {
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
private final KeyPair serverKey;
private final Player player;
private final byte[] sharedSecret;
public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player,
byte[] sharedSecret, KeyPair keyPair) {
this.plugin = plugin;
this.packetEvent = packetEvent;
this.player = player;
this.sharedSecret = Arrays.copyOf(sharedSecret, sharedSecret.length);
this.serverKey = keyPair;
}
@Override
public void run() {
try {
BukkitLoginSession session = plugin.getLoginSessions().get(player.getAddress().toString());
if (session == null) {
disconnect("invalid-request", true
, "GameProfile {0} tried to send encryption response at invalid state", player.getAddress());
} else {
verifyResponse(session);
}
} finally {
//this is a fake packet; it shouldn't be send to the server
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
packetEvent.setCancelled(true);
}
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
}
private void verifyResponse(BukkitLoginSession session) {
PrivateKey privateKey = serverKey.getPrivate();
Cipher cipher;
SecretKey loginKey;
try {
cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
loginKey = EncryptionUtil.decryptSharedKey(cipher, sharedSecret);
} catch (GeneralSecurityException securityEx) {
disconnect("error-kick", false, "Cannot decrypt received contents", securityEx);
return;
}
try {
if (!checkVerifyToken(session, cipher, privateKey) || !encryptConnection(loginKey)) {
return;
}
} catch (Exception ex) {
disconnect("error-kick", false, "Cannot decrypt received contents", ex);
return;
}
String serverId = EncryptionUtil.getServerIdHashString("", loginKey, serverKey.getPublic());
String username = session.getUsername();
InetSocketAddress socketAddress = player.getAddress();
try {
MojangResolver resolver = plugin.getCore().getResolver();
InetAddress address = socketAddress.getAddress();
Optional<Verification> response = resolver.hasJoined(username, serverId, address);
if (response.isPresent()) {
plugin.getLog().info("GameProfile {} has a verified premium account", username);
SkinProperty[] properties = response.get().getProperties();
if (properties.length > 0) {
session.setSkinProperty(properties[0]);
}
session.setUuid(response.get().getId());
session.setVerified(true);
setPremiumUUID(session.getUuid());
receiveFakeStartPacket(username);
} else {
//user tried to fake a authentication
disconnect("invalid-session", true
, "GameProfile {0} ({1}) tried to log in with an invalid session ServerId: {2}"
, session.getUsername(), socketAddress, serverId);
}
} catch (IOException ioEx) {
disconnect("error-kick", false, "Failed to connect to session server", ioEx);
}
}
private void setPremiumUUID(UUID premiumUUID) {
if (plugin.getConfig().getBoolean("premiumUuid") && premiumUUID != null) {
try {
Object networkManager = getNetworkManager();
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/NetworkManager.java#L69
FieldUtils.writeField(networkManager, "spoofedUUID", premiumUUID, true);
} catch (Exception exc) {
plugin.getLog().error("Error setting premium uuid of {}", player, exc);
}
}
}
private boolean checkVerifyToken(BukkitLoginSession session, Cipher cipher, PrivateKey privateKey)
throws GeneralSecurityException {
byte[] requestVerify = session.getVerifyToken();
//encrypted verify token
byte[] responseVerify = packetEvent.getPacket().getByteArrays().read(1);
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(cipher, responseVerify))) {
//check if the verify token are equal to the server sent one
disconnect("invalid-verify-token", true
, "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
, session.getUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
return false;
}
return true;
}
//try to get the networkManager from ProtocolLib
private Object getNetworkManager() throws IllegalAccessException, ClassNotFoundException {
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
//ChannelInjector
Class<?> injectorClass = Class.forName("com.comphenix.protocol.injector.netty.Injector");
Object rawInjector = FuzzyReflection.getFieldValue(injectorContainer, injectorClass, true);
return FieldUtils.readField(rawInjector, "networkManager", true);
}
private boolean encryptConnection(SecretKey loginKey) throws IllegalArgumentException {
try {
//get the NMS connection handle of this player
Object networkManager = getNetworkManager();
//try to detect the method by parameters
Method encryptMethod = FuzzyReflection
.fromObject(networkManager).getMethodByParameters("a", SecretKey.class);
//encrypt/decrypt following packets
//the client expects this behaviour
encryptMethod.invoke(networkManager, loginKey);
} catch (Exception ex) {
disconnect("error-kick", false, "Couldn't enable encryption", ex);
return false;
}
return true;
}
private void disconnect(String reasonKey, boolean debug, String logMessage, Object... arguments) {
if (debug) {
plugin.getLog().debug(logMessage, arguments);
} else {
plugin.getLog().error(logMessage, arguments);
}
kickPlayer(plugin.getCore().getMessage(reasonKey));
}
private void kickPlayer(String reason) {
PacketContainer kickPacket = new PacketContainer(DISCONNECT);
kickPacket.getChatComponents().write(0, WrappedChatComponent.fromText(reason));
try {
//send kick packet at login state
//the normal event.getPlayer.kickPlayer(String) method does only work at play state
ProtocolLibrary.getProtocolManager().sendServerPacket(player, kickPacket);
//tell the server that we want to close the connection
player.kickPlayer("Disconnect");
} catch (InvocationTargetException ex) {
plugin.getLog().error("Error sending kick packet for: {}", player, ex);
}
}
//fake a new login packet in order to let the server handle all the other stuff
private void receiveFakeStartPacket(String username) {
//see StartPacketListener for packet information
PacketContainer startPacket = new PacketContainer(START);
//uuid is ignored by the packet definition
WrappedGameProfile fakeProfile = new WrappedGameProfile(UUID.randomUUID(), username);
startPacket.getGameProfiles().write(0, fakeProfile);
try {
//we don't want to handle our own packets so ignore filters
ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, false);
} catch (InvocationTargetException | IllegalAccessException ex) {
plugin.getLog().warn("Failed to fake a new start packet for: {}", username, ex);
//cancel the event in order to prevent the server receiving an invalid packet
kickPlayer(plugin.getCore().getMessage("error-kick"));
}
}
}

View File

@@ -1,23 +1,20 @@
package com.github.games647.fastlogin.bukkit.listener.protocolsupport;
import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import java.net.InetSocketAddress;
import java.util.Optional;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import protocolsupport.api.events.ConnectionCloseEvent;
import protocolsupport.api.events.PlayerLoginStartEvent;
import protocolsupport.api.events.PlayerProfileCompleteEvent;
import protocolsupport.api.events.PlayerPropertiesResolveEvent;
public class ProtocolSupportListener extends JoinManagement<Player, CommandSender, ProtocolLoginSource>
implements Listener {
@@ -36,7 +33,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
return;
}
String username = loginStartEvent.getConnection().getProfile().getName();
String username = loginStartEvent.getName();
InetSocketAddress address = loginStartEvent.getAddress();
//remove old data every time on a new login in order to keep the session only for one person
@@ -52,28 +49,16 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
}
@EventHandler
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
InetSocketAddress address = profileCompleteEvent.getAddress();
public void onPropertiesResolve(PlayerPropertiesResolveEvent propertiesResolveEvent) {
InetSocketAddress address = propertiesResolveEvent.getAddress();
BukkitLoginSession session = plugin.getLoginSessions().get(address.toString());
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
//skin was resolved -> premium player
if (propertiesResolveEvent.hasProperty(SkinProperty.TEXTURE_KEY) && session != null) {
session.setVerified(true);
if (!plugin.getConfig().getBoolean("premiumUuid")) {
String username = Optional.ofNullable(profileCompleteEvent.getForcedName())
.orElse(profileCompleteEvent.getConnection().getProfile().getName());
profileCompleteEvent.setForcedUUID(UUIDAdapter.generateOfflineId(username));
}
}
}
@Override
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLoginSource source, StoredProfile profile) {
BukkitFastLoginPreLoginEvent event = new BukkitFastLoginPreLoginEvent(username, source, profile);
plugin.getServer().getPluginManager().callEvent(event);
return event;
}
@Override
public void requestPremiumLogin(ProtocolLoginSource source, StoredProfile profile, String username
, boolean registered) {
@@ -85,7 +70,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile);
plugin.getLoginSessions().put(source.getAddress().toString(), playerSession);
if (plugin.getConfig().getBoolean("premiumUuid")) {
source.getLoginStartEvent().setOnlineMode(true);
source.getLoginStartEvent().setUseOnlineModeUUID(true);
}
}

View File

@@ -1,12 +1,12 @@
package com.github.games647.fastlogin.bukkit.task;
package com.github.games647.fastlogin.bukkit.tasks;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.hook.AuthMeHook;
import com.github.games647.fastlogin.bukkit.hook.CrazyLoginHook;
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.hooks.AuthMeHook;
import com.github.games647.fastlogin.bukkit.hooks.CrazyLoginHook;
import com.github.games647.fastlogin.bukkit.hooks.LogItHook;
import com.github.games647.fastlogin.bukkit.hooks.LoginSecurityHook;
import com.github.games647.fastlogin.bukkit.hooks.UltraAuthHook;
import com.github.games647.fastlogin.bukkit.hooks.xAuthHook;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import java.lang.reflect.Constructor;
@@ -36,10 +36,6 @@ public class DelayedAuthHook implements Runnable {
+ "and BungeeCord is deactivated. "
+ "Either one or both of the checks have to pass in order to use this plugin");
}
if (hookFound) {
plugin.setServerStarted();
}
}
private boolean isHookFound() {

View File

@@ -1,18 +1,14 @@
package com.github.games647.fastlogin.bukkit.task;
package com.github.games647.fastlogin.bukkit.tasks;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginAutoLoginEvent;
import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.message.SuccessMessage;
import com.github.games647.fastlogin.core.messages.SuccessMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.ForceLoginManagement;
import com.github.games647.fastlogin.core.shared.LoginSession;
import java.util.concurrent.ExecutionException;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -32,25 +28,11 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
@Override
public void run() {
//blacklist this target player for BungeeCord ID brute force attacks
//blacklist this target player for BungeeCord Id brute force attacks
FastLoginBukkit plugin = core.getPlugin();
player.setMetadata(core.getPlugin().getName(), new FixedMetadataValue(plugin, true));
super.run();
PremiumStatus status = PremiumStatus.CRACKED;
if (isOnlineMode()) {
status = PremiumStatus.PREMIUM;
}
plugin.getPremiumPlayers().put(player.getUniqueId(), status);
}
@Override
public FastLoginAutoLoginEvent callFastLoginAutoLoginEvent(LoginSession session, StoredProfile profile) {
BukkitFastLoginAutoLoginEvent event = new BukkitFastLoginAutoLoginEvent(session, profile);
core.getPlugin().getServer().getPluginManager().callEvent(event);
return event;
}
@Override
@@ -78,10 +60,6 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
@Override
public boolean isOnlineMode() {
if (session == null) {
return false;
}
return session.isVerified() && player.getName().equals(session.getUsername());
}
}

View File

@@ -14,11 +14,11 @@ dev-url: ${project.url}
# Load the plugin as early as possible to inject it for all players
load: STARTUP
# This plugin don't have to be transformed for compatibility with Minecraft >= 1.13
api-version: '1.13'
# We depend either ProtocolLib or ProtocolSupport
depend: [ProtocolLib]
softdepend:
# We depend either ProtocolLib or ProtocolSupport
- ProtocolSupport
- ProtocolLib
- PlaceholderAPI
commands:
${project.parent.name}:

View File

@@ -1,42 +0,0 @@
package com.github.games647.fastlogin.bukkit;
import java.security.SecureRandom;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
public class EncryptionUtilTest {
@Test
public void testVerifyToken() throws Exception {
SecureRandom random = new SecureRandom();
byte[] token = EncryptionUtil.generateVerifyToken(random);
assertThat(token, notNullValue());
assertThat(token.length, is(4));
}
// @Test
// public void testDecryptSharedSecret() throws Exception {
//
// }
//
// @Test
// public void testDecryptData() throws Exception {
//
// }
// private static SecretKey createNewSharedKey() {
// try {
// KeyGenerator keygenerator = KeyGenerator.getInstance("AES");
// keygenerator.init(128);
// return keygenerator.generateKey();
// } catch (NoSuchAlgorithmException nosuchalgorithmexception) {
// throw new Error(nosuchalgorithmexception);
// }
// }
}

Binary file not shown.

View File

@@ -1,11 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.games647</groupId>
<artifactId>fastlogin</artifactId>
<version>1.11-SNAPSHOT</version>
<version>1.11</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -21,7 +21,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<version>3.1.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>false</shadedArtifactAttached>
@@ -56,14 +56,18 @@
</build>
<repositories>
<repository>
<id>vik1395-repo</id>
<url>https://vik1395.github.io/repo.vik1395.me/repositories</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<!--Common plugin component-->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>fastlogin.core</artifactId>
@@ -74,17 +78,21 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>1.14-SNAPSHOT</version>
<version>1.12-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!--Login plugin-->
<dependency>
<groupId>me.vik1395</groupId>
<artifactId>BungeeAuth</artifactId>
<version>1.4</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/BungeeAuth-1.4.jar</systemPath>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@@ -12,28 +12,28 @@ public class BungeeLoginSession extends LoginSession {
super(username, registered, profile);
}
public synchronized void setRegistered(boolean registered) {
public void setRegistered(boolean registered) {
this.registered = registered;
}
public synchronized boolean isAlreadySaved() {
public boolean isAlreadySaved() {
return alreadySaved;
}
public synchronized void setAlreadySaved(boolean alreadySaved) {
public void setAlreadySaved(boolean alreadySaved) {
this.alreadySaved = alreadySaved;
}
public synchronized boolean isAlreadyLogged() {
public boolean isAlreadyLogged() {
return alreadyLogged;
}
public synchronized void setAlreadyLogged(boolean alreadyLogged) {
public void setAlreadyLogged(boolean alreadyLogged) {
this.alreadyLogged = alreadyLogged;
}
@Override
public synchronized String toString() {
public String toString() {
return this.getClass().getSimpleName() + '{' +
"alreadySaved=" + alreadySaved +
", alreadyLogged=" + alreadyLogged +

View File

@@ -4,20 +4,15 @@ import com.github.games647.fastlogin.core.shared.LoginSource;
import java.net.InetSocketAddress;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.PreLoginEvent;
public class BungeeLoginSource implements LoginSource {
private final PendingConnection connection;
private final PreLoginEvent preLoginEvent;
public BungeeLoginSource(PendingConnection connection, PreLoginEvent preLoginEvent) {
public BungeeLoginSource(PendingConnection connection) {
this.connection = connection;
this.preLoginEvent = preLoginEvent;
}
@Override
@@ -27,12 +22,7 @@ public class BungeeLoginSource implements LoginSource {
@Override
public void kick(String message) {
preLoginEvent.setCancelled(true);
if (message != null)
preLoginEvent.setCancelReason(TextComponent.fromLegacyText(message));
else
preLoginEvent.setCancelReason(new ComponentBuilder("Kicked").color(ChatColor.WHITE).create());
connection.disconnect(TextComponent.fromLegacyText(message));
}
@Override

View File

@@ -1,13 +1,10 @@
package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.bungee.hook.BungeeAuthHook;
import com.github.games647.fastlogin.bungee.hooks.BungeeAuthHook;
import com.github.games647.fastlogin.bungee.listener.ConnectListener;
import com.github.games647.fastlogin.bungee.listener.PluginMessageListener;
import com.github.games647.fastlogin.bungee.listener.MessageListener;
import com.github.games647.fastlogin.core.CommonUtil;
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.messages.ChannelMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.google.common.collect.MapMaker;
@@ -51,11 +48,10 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
//events
getProxy().getPluginManager().registerListener(this, new ConnectListener(this));
getProxy().getPluginManager().registerListener(this, new PluginMessageListener(this));
getProxy().getPluginManager().registerListener(this, new MessageListener(this));
//this is required to listen to incoming messages from the server
getProxy().registerChannel(new NamespaceKey(getName(), ChangePremiumMessage.CHANGE_CHANNEL).getCombinedName());
getProxy().registerChannel(new NamespaceKey(getName(), SuccessMessage.SUCCESS_CHANNEL).getCombinedName());
//this is required to listen to messages from the server
getProxy().registerChannel(getName());
registerHook();
}
@@ -86,10 +82,10 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
public void sendPluginMessage(Server server, ChannelMessage message) {
if (server != null) {
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
message.writeTo(dataOutput);
dataOutput.writeUTF(message.getChannelName());
NamespaceKey channel = new NamespaceKey(getName(), message.getChannelName());
server.sendData(channel.getCombinedName(), dataOutput.toByteArray());
message.writeTo(dataOutput);
server.sendData(core.getPlugin().getName(), dataOutput.toByteArray());
}
}
@@ -117,7 +113,7 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
@SuppressWarnings("deprecation")
public ThreadFactory getThreadFactory() {
return new ThreadFactoryBuilder()
.setNameFormat(getName() + " Database Pool Thread #%1$d")
.setNameFormat(core.getPlugin().getName() + " Database Pool Thread #%1$d")
//Hikari create daemons by default
.setDaemon(true)
.setThreadFactory(new GroupedThreadFactory(this, getName()))

View File

@@ -1,39 +0,0 @@
package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
public class BungeeFastLoginAutoLoginEvent extends Event implements FastLoginAutoLoginEvent, Cancellable {
private final LoginSession session;
private final StoredProfile profile;
private boolean cancelled;
public BungeeFastLoginAutoLoginEvent(LoginSession session, StoredProfile profile) {
this.session = session;
this.profile = profile;
}
@Override
public LoginSession getSession() {
return session;
}
@Override
public StoredProfile getProfile() {
return profile;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@@ -1,34 +0,0 @@
package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import net.md_5.bungee.api.plugin.Event;
public class BungeeFastLoginPreLoginEvent extends Event implements FastLoginPreLoginEvent {
private final String username;
private final LoginSource source;
private final StoredProfile profile;
public BungeeFastLoginPreLoginEvent(String username, LoginSource source, StoredProfile profile) {
this.username = username;
this.source = source;
this.profile = profile;
}
@Override
public String getUsername() {
return username;
}
@Override
public LoginSource getSource() {
return source;
}
@Override
public StoredProfile getProfile() {
return profile;
}
}

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bungee.hook;
package com.github.games647.fastlogin.bungee.hooks;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;

View File

@@ -2,8 +2,8 @@ package com.github.games647.fastlogin.bungee.listener;
import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.task.AsyncPremiumCheck;
import com.github.games647.fastlogin.bungee.task.ForceLoginTask;
import com.github.games647.fastlogin.bungee.tasks.AsyncPremiumCheck;
import com.github.games647.fastlogin.bungee.tasks.ForceLoginTask;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;

View File

@@ -2,11 +2,9 @@ package com.github.games647.fastlogin.bungee.listener;
import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.task.AsyncToggleMessage;
import com.github.games647.fastlogin.bungee.tasks.AsyncToggleMessage;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.message.SuccessMessage;
import com.github.games647.fastlogin.core.messages.ChangePremiumMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
@@ -22,24 +20,18 @@ import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class PluginMessageListener implements Listener {
public class MessageListener implements Listener {
private final FastLoginBungee plugin;
private final String successChannel;
private final String changeChannel;
public PluginMessageListener(FastLoginBungee plugin) {
public MessageListener(FastLoginBungee plugin) {
this.plugin = plugin;
this.successChannel = new NamespaceKey(plugin.getName(), SuccessMessage.SUCCESS_CHANNEL).getCombinedName();
this.changeChannel = new NamespaceKey(plugin.getName(), ChangePremiumMessage.CHANGE_CHANNEL).getCombinedName();
}
@EventHandler
public void onPluginMessage(PluginMessageEvent pluginMessageEvent) {
String channel = pluginMessageEvent.getTag();
if (pluginMessageEvent.isCancelled() || !channel.startsWith(plugin.getName().toLowerCase())) {
if (pluginMessageEvent.isCancelled() || !plugin.getName().equals(channel)) {
return;
}
@@ -56,16 +48,17 @@ public class PluginMessageListener implements Listener {
byte[] data = Arrays.copyOf(pluginMessageEvent.getData(), pluginMessageEvent.getData().length);
ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver();
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> readMessage(forPlayer, channel, data));
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> readMessage(forPlayer, data));
}
private void readMessage(ProxiedPlayer forPlayer, String channel, byte[] data) {
private void readMessage(ProxiedPlayer forPlayer, byte[] data) {
FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core = plugin.getCore();
ByteArrayDataInput dataInput = ByteStreams.newDataInput(data);
if (successChannel.equals(channel)) {
String subChannel = dataInput.readUTF();
if ("Success".equals(subChannel)) {
onSuccessMessage(forPlayer);
} else if (changeChannel.equals(channel)) {
} else if ("ChangeStatus".equals(subChannel)) {
ChangePremiumMessage changeMessage = new ChangePremiumMessage();
changeMessage.readFrom(dataInput);

View File

@@ -1,28 +1,26 @@
package com.github.games647.fastlogin.bungee.task;
package com.github.games647.fastlogin.bungee.tasks;
import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.BungeeLoginSource;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.event.AsyncEvent;
import net.md_5.bungee.connection.InitialHandler;
public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSender, BungeeLoginSource>
implements Runnable {
private final FastLoginBungee plugin;
private final PreLoginEvent preLoginEvent;
private final AsyncEvent<?> preLoginEvent;
private final PendingConnection connection;
public AsyncPremiumCheck(FastLoginBungee plugin, PreLoginEvent preLoginEvent, PendingConnection connection) {
public AsyncPremiumCheck(FastLoginBungee plugin, AsyncEvent<?> preLoginEvent, PendingConnection connection) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
this.plugin = plugin;
@@ -37,19 +35,12 @@ public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSend
InitialHandler initialHandler = (InitialHandler) connection;
String username = initialHandler.getLoginRequest().getData();
try {
super.onLogin(username, new BungeeLoginSource(connection, preLoginEvent));
super.onLogin(username, new BungeeLoginSource(connection));
} finally {
preLoginEvent.completeIntent(plugin);
}
}
@Override
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, BungeeLoginSource source,
StoredProfile profile) {
return plugin.getProxy().getPluginManager()
.callEvent(new BungeeFastLoginPreLoginEvent(username, source, profile));
}
@Override
public void requestPremiumLogin(BungeeLoginSource source, StoredProfile profile,
String username, boolean registered) {

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bungee.task;
package com.github.games647.fastlogin.bungee.tasks;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.core.StoredProfile;

View File

@@ -1,19 +1,16 @@
package com.github.games647.fastlogin.bungee.task;
package com.github.games647.fastlogin.bungee.tasks;
import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginAutoLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage.Type;
import com.github.games647.fastlogin.core.messages.ChannelMessage;
import com.github.games647.fastlogin.core.messages.LoginActionMessage;
import com.github.games647.fastlogin.core.messages.LoginActionMessage.Type;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.ForceLoginManagement;
import com.github.games647.fastlogin.core.shared.LoginSession;
import java.util.UUID;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -54,15 +51,10 @@ public class ForceLoginTask
return super.forceLogin(player);
}
@Override
public FastLoginAutoLoginEvent callFastLoginAutoLoginEvent(LoginSession session, StoredProfile profile) {
return core.getPlugin().getProxy().getPluginManager()
.callEvent(new BungeeFastLoginAutoLoginEvent(session, profile));
}
@Override
public boolean forceRegister(ProxiedPlayer player) {
return session.isAlreadyLogged() || super.forceRegister(player);
}
@Override
@@ -70,7 +62,7 @@ public class ForceLoginTask
//sub channel name
Type type = Type.LOGIN;
if (session.needsRegistration()) {
type = Type.REGISTER;
type = Type.LOGIN;
}
UUID proxyId = UUID.fromString(ProxyServer.getInstance().getConfig().getUuid());

View File

@@ -1,11 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.games647</groupId>
<artifactId>fastlogin</artifactId>
<version>1.11-SNAPSHOT</version>
<version>1.11</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -18,13 +18,11 @@
<repository>
<id>luck-repo</id>
<url>https://ci.lucko.me/plugin/repository/everything</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
</repositories>
@@ -35,14 +33,14 @@
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.2</version>
<version>2.7.8</version>
</dependency>
<!--Logging framework implements slf4j which is required by hikari-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.30</version>
<version>1.7.25</version>
</dependency>
<!--GSON is not at the right position for Minecraft 1.7-->
@@ -65,11 +63,10 @@
</exclusions>
</dependency>
<!--Common component for contacting the Mojang API-->
<dependency>
<groupId>com.github.games647</groupId>
<artifactId>craftapi</artifactId>
<version>0.3</version>
<version>0.1.3-SNAPSHOT</version>
</dependency>
<!-- APIs we can use because they are available in all platforms (Spigot, Bungee, Cauldron) -->

View File

@@ -22,34 +22,40 @@ public class AuthStorage {
private static final String PREMIUM_TABLE = "premium";
private static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE + "` WHERE `Name`=? LIMIT 1";
private static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE + "` WHERE `UUID`=? LIMIT 1";
private static final String INSERT_PROFILE = "INSERT INTO `" + PREMIUM_TABLE
+ "` (`UUID`, `Name`, `Premium`, `LastIp`) " + "VALUES (?, ?, ?, ?) ";
// limit not necessary here, because it's unique
private static final String UPDATE_PROFILE = "UPDATE `" + PREMIUM_TABLE
+ "` SET `UUID`=?, `Name`=?, `Premium`=?, `LastIp`=?, `LastLogin`=CURRENT_TIMESTAMP WHERE `UserID`=?";
private static final String LOAD_BY_NAME = "SELECT * FROM " + PREMIUM_TABLE + " WHERE Name=? LIMIT 1";
private static final String LOAD_BY_UUID = "SELECT * FROM " + PREMIUM_TABLE + " WHERE UUID=? LIMIT 1";
private static final String INSERT_PROFILE = "INSERT INTO " + PREMIUM_TABLE + " (UUID, Name, Premium, LastIp) "
+ "VALUES (?, ?, ?, ?) ";
private static final String UPDATE_PROFILE = "UPDATE " + PREMIUM_TABLE
+ " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=CURRENT_TIMESTAMP WHERE UserID=?";
private final FastLoginCore<?, ?, ?> core;
private final HikariDataSource dataSource;
public AuthStorage(FastLoginCore<?, ?, ?> core, String host, int port, String databasePath,
HikariConfig config, boolean useSSL) {
public AuthStorage(FastLoginCore<?, ?, ?> core, String driver, String host, int port, String databasePath
, String user, String pass, boolean useSSL) {
this.core = core;
HikariConfig config = new HikariConfig();
config.setPoolName(core.getPlugin().getName());
config.setUsername(user);
config.setPassword(pass);
config.setDriverClassName(driver);
//a try to fix https://www.spigotmc.org/threads/fastlogin.101192/page-26#post-1874647
Properties properties = new Properties();
properties.setProperty("date_string_format", "yyyy-MM-dd HH:mm:ss");
properties.setProperty("useSSL", String.valueOf(useSSL));
config.setDataSourceProperties(properties);
ThreadFactory platformThreadFactory = core.getPlugin().getThreadFactory();
if (platformThreadFactory != null) {
config.setThreadFactory(platformThreadFactory);
}
String jdbcUrl = "jdbc:";
if (config.getDriverClassName().contains("sqlite")) {
if (driver.contains("sqlite")) {
String pluginFolder = core.getPlugin().getPluginFolder().toAbsolutePath().toString();
databasePath = databasePath.replace("{pluginDir}", pluginFolder);
@@ -58,13 +64,6 @@ public class AuthStorage {
config.setMaximumPoolSize(1);
} else {
jdbcUrl += "mysql://" + host + ':' + port + '/' + databasePath;
// enable MySQL specific optimizations
// default prepStmtCacheSize 25 - amount of cached statements - enough for us
// default prepStmtCacheSqlLimit 256 - length of SQL - our queries are not longer
// disabled by default - will return the same prepared statement instance
config.addDataSourceProperty("cachePrepStmts", true);
// default false - available in newer versions caches the statements server-side
config.addDataSourceProperty("useServerPrepStmts", true);
}
config.setJdbcUrl(jdbcUrl);
@@ -72,24 +71,23 @@ public class AuthStorage {
}
public void createTables() throws SQLException {
String createDataStmt = "CREATE TABLE IF NOT EXISTS `" + PREMIUM_TABLE + "` ("
+ "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, "
+ "`UUID` CHAR(36), "
+ "`Name` VARCHAR(16) NOT NULL, "
+ "`Premium` BOOLEAN NOT NULL, "
+ "`LastIp` VARCHAR(255) NOT NULL, "
+ "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
//the premium shouldn't steal the cracked account by changing the name
+ "UNIQUE (`Name`) "
+ ')';
if (dataSource.getJdbcUrl().contains("sqlite")) {
createDataStmt = createDataStmt.replace("AUTO_INCREMENT", "AUTOINCREMENT");
}
//todo: add uuid index usage
try (Connection con = dataSource.getConnection();
Statement createStmt = con.createStatement()) {
String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " ("
+ "UserID INTEGER PRIMARY KEY AUTO_INCREMENT, "
+ "UUID CHAR(36), "
+ "Name VARCHAR(16) NOT NULL, "
+ "Premium BOOLEAN NOT NULL, "
+ "LastIp VARCHAR(255) NOT NULL, "
+ "LastLogin TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
//the premium shouldn't steal the cracked account by changing the name
+ "UNIQUE (Name) "
+ ')';
if (dataSource.getJdbcUrl().contains("sqlite")) {
createDataStmt = createDataStmt.replace("AUTO_INCREMENT", "AUTOINCREMENT");
}
createStmt.executeUpdate(createDataStmt);
}
}

View File

@@ -2,11 +2,9 @@ package com.github.games647.fastlogin.core.hooks;
import java.security.SecureRandom;
import java.util.Random;
import java.util.stream.IntStream;
public class DefaultPasswordGenerator<P> implements PasswordGenerator<P> {
private static final int PASSWORD_LENGTH = 8;
private static final char[] PASSWORD_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
.toCharArray();
@@ -15,10 +13,9 @@ public class DefaultPasswordGenerator<P> implements PasswordGenerator<P> {
@Override
public String getRandomPassword(P player) {
StringBuilder generatedPassword = new StringBuilder(8);
IntStream.rangeClosed(1, PASSWORD_LENGTH)
.map(i -> random.nextInt(PASSWORD_CHARACTERS.length - 1))
.mapToObj(pos -> PASSWORD_CHARACTERS[pos])
.forEach(generatedPassword::append);
for (int i = 1; i <= 8; i++) {
generatedPassword.append(PASSWORD_CHARACTERS[random.nextInt(PASSWORD_CHARACTERS.length - 1)]);
}
return generatedPassword.toString();
}

View File

@@ -1,26 +0,0 @@
package com.github.games647.fastlogin.core.message;
public class NamespaceKey {
private static final char SEPARATOR_CHAR = ':';
private final String namespace;
private final String key;
private final String combined;
public NamespaceKey(String namespace, String key) {
this.namespace = namespace.toLowerCase();
this.key = key.toLowerCase();
this.combined = this.namespace + SEPARATOR_CHAR + this.key;
}
public String getCombinedName() {
return combined;
}
public static String getCombined(String namespace, String key) {
return new NamespaceKey(namespace, key).combined;
}
}

View File

@@ -1,12 +1,10 @@
package com.github.games647.fastlogin.core.message;
package com.github.games647.fastlogin.core.messages;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
public class ChangePremiumMessage implements ChannelMessage {
public static final String CHANGE_CHANNEL = "ch-st";
private String playerName;
private boolean willEnable;
private boolean isSourceInvoker;
@@ -35,7 +33,7 @@ public class ChangePremiumMessage implements ChannelMessage {
@Override
public String getChannelName() {
return CHANGE_CHANNEL;
return "ChangeStatus";
}
@Override

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.core.message;
package com.github.games647.fastlogin.core.messages;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;

View File

@@ -1,4 +1,4 @@
package com.github.games647.fastlogin.core.message;
package com.github.games647.fastlogin.core.messages;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
@@ -7,8 +7,6 @@ import java.util.UUID;
public class LoginActionMessage implements ChannelMessage {
public static final String FORCE_CHANNEL = "force";
private Type type;
private String playerName;
@@ -62,7 +60,7 @@ public class LoginActionMessage implements ChannelMessage {
@Override
public String getChannelName() {
return FORCE_CHANNEL;
return "LoginAction";
}
@Override

View File

@@ -1,15 +1,13 @@
package com.github.games647.fastlogin.core.message;
package com.github.games647.fastlogin.core.messages;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
public class SuccessMessage implements ChannelMessage {
public static final String SUCCESS_CHANNEL = "succ";
@Override
public String getChannelName() {
return SUCCESS_CHANNEL;
return "Success";
}
@Override

View File

@@ -8,11 +8,9 @@ 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.google.common.net.HostAndPort;
import com.zaxxer.hikari.HikariConfig;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
@@ -76,7 +74,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
.forEach((key, message) -> {
String colored = CommonUtil.translateColorCodes((String) message);
if (!colored.isEmpty()) {
localeMessages.put(key, colored.replace("/newline", "\n"));
localeMessages.put(key, colored);
}
});
} catch (IOException ioEx) {
@@ -105,26 +103,15 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
}
private Configuration loadFile(String fileName) throws IOException {
ConfigurationProvider configProvider = ConfigurationProvider.getProvider(YamlConfiguration.class);
Configuration defaults;
ConfigurationProvider configProvider = ConfigurationProvider.getProvider(YamlConfiguration.class);
try (InputStream defaultStream = getClass().getClassLoader().getResourceAsStream(fileName)) {
defaults = configProvider.load(defaultStream);
}
Path file = plugin.getPluginFolder().resolve(fileName);
Configuration config;
try (Reader reader = Files.newBufferedReader(file)) {
config = configProvider.load(reader, defaults);
}
//explicitly add keys here, because Configuration.getKeys doesn't return the keys from the default configuration
for (String key : defaults.getKeys()) {
config.set(key, config.get(key));
}
return config;
return configProvider.load(Files.newBufferedReader(file), defaults);
}
public MojangResolver getResolver() {
@@ -142,7 +129,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
public void sendLocaleMessage(String key, C receiver) {
String message = localeMessages.get(key);
if (message != null) {
plugin.sendMultiLineMessage(receiver, message);
plugin.sendMessage(receiver, message);
}
}
@@ -151,9 +138,8 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
}
public boolean setupDatabase() {
HikariConfig databaseConfig = new HikariConfig();
databaseConfig.setDriverClassName(config.getString("driver"));
if (!checkDriver(databaseConfig.getDriverClassName())) {
String driver = config.getString("driver");
if (!checkDriver(driver)) {
return false;
}
@@ -161,15 +147,12 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
int port = config.get("port", 3306);
String database = config.getString("database");
String user = config.get("username", "");
String password = config.get("password", "");
boolean useSSL = config.get("useSSL", false);
databaseConfig.setUsername(config.get("username", ""));
databaseConfig.setPassword(config.getString("password"));
databaseConfig.setConnectionTimeout(config.getInt("timeout", 30) * 1_000L);
databaseConfig.setMaxLifetime(config.getInt("lifetime", 30) * 1_000L);
storage = new AuthStorage(this, host, port, database, databaseConfig, useSSL);
storage = new AuthStorage(this, driver, host, port, database, user, password, useSSL);
try {
storage.createTables();
return true;
@@ -192,6 +175,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
return false;
}
public Configuration getConfig() {
return config;
}

View File

@@ -3,7 +3,6 @@ package com.github.games647.fastlogin.core.shared;
import com.github.games647.fastlogin.core.AuthStorage;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
public abstract class ForceLoginManagement<P extends C, C, L extends LoginSession, T extends PlatformPlugin<C>>
implements Runnable {
@@ -25,6 +24,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
}
AuthStorage storage = core.getStorage();
StoredProfile playerProfile = session.getProfile();
try {
if (isOnlineMode()) {
@@ -41,7 +41,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
|| (core.getConfig().get("auto-register-unknown", false)
&& !authPlugin.isRegistered(playerName))) {
success = forceRegister(player);
} else if (!callFastLoginAutoLoginEvent(session, playerProfile).isCancelled()) {
} else {
success = forceLogin(player);
}
}
@@ -85,8 +85,8 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
public boolean forceLogin(P player) {
core.getPlugin().getLog().info("Logging player {} in", getName(player));
boolean success = core.getAuthPluginHook().forceLogin(player);
if (success) {
core.sendLocaleMessage("auto-login", player);
}
@@ -94,8 +94,6 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
return success;
}
public abstract FastLoginAutoLoginEvent callFastLoginAutoLoginEvent(LoginSession session, StoredProfile profile);
public abstract void onForceActionSuccess(LoginSession session);
public abstract String getName(P player);

View File

@@ -4,7 +4,6 @@ import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.util.Optional;
@@ -26,8 +25,6 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
return;
}
callFastLoginPreLoginEvent(username, source, profile);
Configuration config = core.getConfig();
String ip = source.getAddress().getAddress().getHostAddress();
@@ -104,8 +101,6 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
return false;
}
public abstract FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, S source, StoredProfile profile);
public abstract void requestPremiumLogin(S source, StoredProfile profile, String username, boolean registered);
public abstract void startCrackedSession(S source, StoredProfile profile, String username);

View File

@@ -15,12 +15,6 @@ public interface PlatformPlugin<C> {
void sendMessage(C receiver, String message);
default void sendMultiLineMessage(C receiver, String message) {
for (String line : message.split("%nl%")) {
sendMessage(receiver, line);
}
}
default ThreadFactory getThreadFactory() {
return null;
}

View File

@@ -1,9 +0,0 @@
package com.github.games647.fastlogin.core.shared.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
public interface FastLoginAutoLoginEvent extends FastLoginCancellableEvent {
LoginSession getSession();
StoredProfile getProfile();
}

View File

@@ -1,7 +0,0 @@
package com.github.games647.fastlogin.core.shared.event;
public interface FastLoginCancellableEvent {
boolean isCancelled();
void setCancelled(boolean cancelled);
}

View File

@@ -1,11 +0,0 @@
package com.github.games647.fastlogin.core.shared.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource;
public interface FastLoginPreLoginEvent {
String getUsername();
LoginSource getSource();
StoredProfile getProfile();
}

View File

@@ -161,22 +161,17 @@ autoLogin: true
# Recommended is the use of MariaDB (a better version of MySQL)
# Single file SQLite database
driver: 'org.sqlite.JDBC'
driver: org.sqlite.JDBC
# File location
database: '{pluginDir}/FastLogin.db'
# MySQL/MariaDB
# If you want to enable it uncomment only the lines below this not this line.
#driver: 'com.mysql.jdbc.Driver'
#host: '127.0.0.1'
#driver: com.mysql.jdbc.Driver
#host: 127.0.0.1
#port: 3306
#database: 'fastlogin'
#username: 'myUser'
#password: 'myPassword'
# Advanced Connection Pool settings in seconds
#timeout: 30
#lifetime: 30
#database: fastlogin
#username: myUser
#password: myPassword
# It's strongly recommended to enable SSL and setup a SSL certificate if the MySQL server isn't running on the same
# machine

25
pom.xml
View File

@@ -1,5 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.games647</groupId>
@@ -8,11 +8,11 @@
<packaging>pom</packaging>
<name>FastLogin</name>
<version>1.11-SNAPSHOT</version>
<version>1.11</version>
<url>https://www.spigotmc.org/resources/fastlogin.14153/</url>
<description>
Automatically login premium (paid accounts) player on a offline mode server
Automatically logins premium (paid accounts) player on a offline mode server
</description>
<properties>
@@ -21,9 +21,8 @@
<!-- Set default for non-git clones -->
<git.commit.id>Unknown</git.commit.id>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<modules>
@@ -32,18 +31,6 @@
<module>bungee</module>
</modules>
<!--Deployment configuration for the Maven repository-->
<distributionManagement>
<snapshotRepository>
<id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>codemc-releases</id>
<url>https://repo.codemc.io/repository/maven-releases/</url>
</repository>
</distributionManagement>
<build>
<!--Just use the project name to replace an old version of the plugin if the user does only copy-paste-->
<finalName>${project.name}</finalName>
@@ -52,7 +39,7 @@
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.0.0</version>
<version>2.2.4</version>
<configuration>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
</configuration>