forked from TuxCoding/FastLogin
Use direct proxies instead of ssl factories for multiple IP-addresses
This commit is contained in:
@ -1,5 +1,9 @@
|
|||||||
### 1.11
|
### 1.11
|
||||||
|
|
||||||
|
* Use direct proxies instead of ssl factories for multiple IP-addresses
|
||||||
|
* Remove local address check for multiple IP-addresses
|
||||||
|
* Fix parsing of local IP-addresses
|
||||||
|
* Fix address rotating for contacting the Mojang API
|
||||||
* Optimize issue template
|
* Optimize issue template
|
||||||
* Use Instant for timestamps
|
* Use Instant for timestamps
|
||||||
* Migrate SLF4J logging (Fixes #177)
|
* Migrate SLF4J logging (Fixes #177)
|
||||||
|
@ -36,7 +36,7 @@ public class CrackedCommand implements CommandExecutor {
|
|||||||
plugin.getCore().sendLocaleMessage("remove-premium", sender);
|
plugin.getCore().sendLocaleMessage("remove-premium", sender);
|
||||||
|
|
||||||
profile.setPremium(false);
|
profile.setPremium(false);
|
||||||
profile.setUuid(null);
|
profile.setUUID(null);
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
plugin.getCore().getStorage().save(profile);
|
plugin.getCore().getStorage().save(profile);
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,6 @@ import com.lenis0012.bukkit.loginsecurity.session.action.LoginAction;
|
|||||||
import com.lenis0012.bukkit.loginsecurity.session.action.RegisterAction;
|
import com.lenis0012.bukkit.loginsecurity.session.action.RegisterAction;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Github: https://github.com/lenis0012/LoginSecurity-2 Project page:
|
* Github: https://github.com/lenis0012/LoginSecurity-2 Project page:
|
||||||
@ -19,7 +18,11 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
*/
|
*/
|
||||||
public class LoginSecurityHook implements AuthPlugin<Player> {
|
public class LoginSecurityHook implements AuthPlugin<Player> {
|
||||||
|
|
||||||
private final FastLoginBukkit plugin = JavaPlugin.getPlugin(FastLoginBukkit.class);
|
private final FastLoginBukkit plugin;
|
||||||
|
|
||||||
|
public LoginSecurityHook(FastLoginBukkit plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean forceLogin(Player player) {
|
public boolean forceLogin(Player player) {
|
||||||
|
@ -8,8 +8,9 @@ import com.github.games647.fastlogin.bukkit.hooks.LoginSecurityHook;
|
|||||||
import com.github.games647.fastlogin.bukkit.hooks.UltraAuthHook;
|
import com.github.games647.fastlogin.bukkit.hooks.UltraAuthHook;
|
||||||
import com.github.games647.fastlogin.bukkit.hooks.xAuthHook;
|
import com.github.games647.fastlogin.bukkit.hooks.xAuthHook;
|
||||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -41,28 +42,7 @@ public class DelayedAuthHook implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean registerHooks() {
|
private boolean registerHooks() {
|
||||||
AuthPlugin<Player> authPluginHook = null;
|
AuthPlugin<Player> authPluginHook = getAuthHook();
|
||||||
|
|
||||||
try {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<Class<? extends AuthPlugin<Player>>> supportedHooks = Lists.newArrayList(AuthMeHook.class
|
|
||||||
, CrazyLoginHook.class, LogItHook.class, LoginSecurityHook.class, UltraAuthHook.class
|
|
||||||
, xAuthHook.class);
|
|
||||||
|
|
||||||
for (Class<? extends AuthPlugin<Player>> clazz : supportedHooks) {
|
|
||||||
String pluginName = clazz.getSimpleName().replace("Hook", "");
|
|
||||||
//uses only member classes which uses AuthPlugin interface (skip interfaces)
|
|
||||||
if (Bukkit.getPluginManager().isPluginEnabled(pluginName)) {
|
|
||||||
//check only for enabled plugins. A single plugin could be disabled by plugin managers
|
|
||||||
authPluginHook = clazz.newInstance();
|
|
||||||
plugin.getLog().info("Hooking into auth plugin: {}", pluginName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InstantiationException | IllegalAccessException ex) {
|
|
||||||
plugin.getLog().error("Couldn't load the integration class", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authPluginHook == null) {
|
if (authPluginHook == null) {
|
||||||
//run this check for exceptions (errors) and not found plugins
|
//run this check for exceptions (errors) and not found plugins
|
||||||
plugin.getLog().warn("No support offline Auth plugin found. ");
|
plugin.getLog().warn("No support offline Auth plugin found. ");
|
||||||
@ -70,9 +50,42 @@ public class DelayedAuthHook implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.getCore().getAuthPluginHook() == null) {
|
if (plugin.getCore().getAuthPluginHook() == null) {
|
||||||
|
plugin.getLog().info("Hooking into auth plugin: {}", authPluginHook.getClass().getSimpleName());
|
||||||
plugin.getCore().setAuthPluginHook(authPluginHook);
|
plugin.getCore().setAuthPluginHook(authPluginHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuthPlugin<Player> getAuthHook() {
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Class<? extends AuthPlugin<Player>>> hooks = Arrays.asList(AuthMeHook.class,
|
||||||
|
CrazyLoginHook.class, LogItHook.class, LoginSecurityHook.class, UltraAuthHook.class,
|
||||||
|
xAuthHook.class);
|
||||||
|
|
||||||
|
for (Class<? extends AuthPlugin<Player>> clazz : hooks) {
|
||||||
|
String pluginName = clazz.getSimpleName().replace("Hook", "");
|
||||||
|
//uses only member classes which uses AuthPlugin interface (skip interfaces)
|
||||||
|
if (Bukkit.getPluginManager().isPluginEnabled(pluginName)) {
|
||||||
|
//check only for enabled plugins. A single plugin could be disabled by plugin managers
|
||||||
|
return newInstance(clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ReflectiveOperationException ex) {
|
||||||
|
plugin.getLog().error("Couldn't load the integration class", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthPlugin<Player> newInstance(Class<? extends AuthPlugin<Player>> clazz)
|
||||||
|
throws ReflectiveOperationException {
|
||||||
|
try {
|
||||||
|
Constructor<? extends AuthPlugin<Player>> cons = clazz.getConstructor(FastLoginBukkit.class);
|
||||||
|
return cons.newInstance(plugin);
|
||||||
|
} catch (NoSuchMethodException noMethodEx) {
|
||||||
|
return clazz.newInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class ConnectListener implements Listener {
|
|||||||
session.setUuid(connection.getUniqueId());
|
session.setUuid(connection.getUniqueId());
|
||||||
|
|
||||||
PlayerProfile playerProfile = session.getProfile();
|
PlayerProfile playerProfile = session.getProfile();
|
||||||
playerProfile.setUuid(connection.getUniqueId());
|
playerProfile.setUUID(connection.getUniqueId());
|
||||||
|
|
||||||
//bungeecord will do this automatically so override it on disabled option
|
//bungeecord will do this automatically so override it on disabled option
|
||||||
if (!plugin.getCore().getConfig().get("premiumUuid", true)) {
|
if (!plugin.getCore().getConfig().get("premiumUuid", true)) {
|
||||||
|
@ -44,7 +44,7 @@ public class AsyncToggleMessage implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
playerProfile.setPremium(false);
|
playerProfile.setPremium(false);
|
||||||
playerProfile.setUuid(null);
|
playerProfile.setUUID(null);
|
||||||
core.getStorage().save(playerProfile);
|
core.getStorage().save(playerProfile);
|
||||||
sendMessage("remove-premium");
|
sendMessage("remove-premium");
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ public class ForceLoginTask
|
|||||||
public void run() {
|
public void run() {
|
||||||
PendingConnection pendingConnection = player.getPendingConnection();
|
PendingConnection pendingConnection = player.getPendingConnection();
|
||||||
session = core.getPlugin().getSession().get(pendingConnection);
|
session = core.getPlugin().getSession().get(pendingConnection);
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
<version>2.7.1</version>
|
<version>2.7.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--Logging framework implements slf4j which is required by hikari-->
|
<!--Logging framework implements slf4j which is required by hikari-->
|
||||||
|
@ -138,7 +138,7 @@ public class AuthStorage {
|
|||||||
|
|
||||||
public void save(PlayerProfile playerProfile) {
|
public void save(PlayerProfile playerProfile) {
|
||||||
try (Connection con = dataSource.getConnection()) {
|
try (Connection con = dataSource.getConnection()) {
|
||||||
UUID uuid = playerProfile.getUuid();
|
UUID uuid = playerProfile.getUUID();
|
||||||
|
|
||||||
if (playerProfile.getUserId() == -1) {
|
if (playerProfile.getUserId() == -1) {
|
||||||
try (PreparedStatement saveStmt = con.prepareStatement(INSERT_PROFILE, RETURN_GENERATED_KEYS)) {
|
try (PreparedStatement saveStmt = con.prepareStatement(INSERT_PROFILE, RETURN_GENERATED_KEYS)) {
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package com.github.games647.fastlogin.core;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
|
|
||||||
public class BalancedSSLFactory extends SSLSocketFactory {
|
|
||||||
|
|
||||||
//in order to be thread-safe
|
|
||||||
private final Iterator<InetAddress> iterator;
|
|
||||||
private final SSLSocketFactory oldFactory;
|
|
||||||
|
|
||||||
public BalancedSSLFactory(SSLSocketFactory oldFactory, Iterable<InetAddress> localAddresses) {
|
|
||||||
this.oldFactory = oldFactory;
|
|
||||||
this.iterator = Iterables.cycle(localAddresses).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getDefaultCipherSuites() {
|
|
||||||
return oldFactory.getDefaultCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getSupportedCipherSuites() {
|
|
||||||
return oldFactory.getSupportedCipherSuites();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
|
|
||||||
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port) throws IOException {
|
|
||||||
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort)
|
|
||||||
throws IOException {
|
|
||||||
//default
|
|
||||||
return oldFactory.createSocket(host, port, localAddress, localPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
||||||
return oldFactory.createSocket(host, port, getNextLocalAddress(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(InetAddress host, int port, InetAddress local, int localPort) throws IOException {
|
|
||||||
//Default
|
|
||||||
return oldFactory.createSocket(host, port, local, localPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
private InetAddress getNextLocalAddress() {
|
|
||||||
synchronized (iterator) {
|
|
||||||
return iterator.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -43,11 +43,12 @@ public class PlayerProfile {
|
|||||||
this.userId = generatedId;
|
this.userId = generatedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized UUID getUuid() {
|
//todo: this should be optional
|
||||||
|
public synchronized UUID getUUID() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setUuid(UUID uuid) {
|
public synchronized void setUUID(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package com.github.games647.fastlogin.core.mojang;
|
package com.github.games647.fastlogin.core.mojang;
|
||||||
|
|
||||||
import com.github.games647.fastlogin.core.BalancedSSLFactory;
|
|
||||||
import com.github.games647.fastlogin.core.CommonUtil;
|
import com.github.games647.fastlogin.core.CommonUtil;
|
||||||
import com.github.games647.fastlogin.core.shared.LoginSession;
|
import com.github.games647.fastlogin.core.shared.LoginSession;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.common.net.HostAndPort;
|
import com.google.common.net.HostAndPort;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
@ -14,12 +12,10 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.net.Proxy.Type;
|
import java.net.Proxy.Type;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
@ -28,12 +24,10 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@ -53,7 +47,6 @@ public class MojangApiConnector {
|
|||||||
|
|
||||||
private final Iterator<Proxy> proxies;
|
private final Iterator<Proxy> proxies;
|
||||||
private final Map<Object, Object> requests = CommonUtil.buildCache(10, -1);
|
private final Map<Object, Object> requests = CommonUtil.buildCache(10, -1);
|
||||||
private final SSLSocketFactory sslFactory;
|
|
||||||
private final int rateLimit;
|
private final int rateLimit;
|
||||||
|
|
||||||
private Instant lastRateLimit = Instant.now().minus(10, ChronoUnit.MINUTES);
|
private Instant lastRateLimit = Instant.now().minus(10, ChronoUnit.MINUTES);
|
||||||
@ -65,13 +58,16 @@ public class MojangApiConnector {
|
|||||||
, Iterable<HostAndPort> proxies) {
|
, Iterable<HostAndPort> proxies) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.rateLimit = Math.max(rateLimit, 600);
|
this.rateLimit = Math.max(rateLimit, 600);
|
||||||
this.sslFactory = buildAddresses(logger, localAddresses);
|
|
||||||
|
|
||||||
List<Proxy> proxyBuilder = Lists.newArrayList();
|
List<Proxy> proxyBuilder = Lists.newArrayList();
|
||||||
for (HostAndPort proxy : proxies) {
|
for (HostAndPort proxy : proxies) {
|
||||||
proxyBuilder.add(new Proxy(Type.HTTP, new InetSocketAddress(proxy.getHostText(), proxy.getPort())));
|
proxyBuilder.add(new Proxy(Type.HTTP, new InetSocketAddress(proxy.getHostText(), proxy.getPort())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String address : localAddresses) {
|
||||||
|
proxyBuilder.add(new Proxy(Type.DIRECT, new InetSocketAddress(address.replace('-', '.'), 0)));
|
||||||
|
}
|
||||||
|
|
||||||
this.proxies = Iterables.cycle(proxyBuilder).iterator();
|
this.proxies = Iterables.cycle(proxyBuilder).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +138,6 @@ public class MojangApiConnector {
|
|||||||
connection.setRequestProperty("Content-Type", "application/json");
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
connection.setRequestProperty("User-Agent", USER_AGENT);
|
connection.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
connection.setSSLSocketFactory(sslFactory);
|
|
||||||
|
|
||||||
//this connection doesn't need to be closed. So can make use of keep alive in java
|
//this connection doesn't need to be closed. So can make use of keep alive in java
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
@ -151,22 +145,4 @@ public class MojangApiConnector {
|
|||||||
protected HttpsURLConnection getConnection(String url) throws IOException {
|
protected HttpsURLConnection getConnection(String url) throws IOException {
|
||||||
return getConnection(url, Proxy.NO_PROXY);
|
return getConnection(url, Proxy.NO_PROXY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SSLSocketFactory buildAddresses(Logger logger, Iterable<String> localAddresses) {
|
|
||||||
Set<InetAddress> addresses = Sets.newHashSet();
|
|
||||||
for (String localAddress : localAddresses) {
|
|
||||||
try {
|
|
||||||
InetAddress address = InetAddress.getByName(localAddress.replace('-', '.'));
|
|
||||||
addresses.add(address);
|
|
||||||
} catch (UnknownHostException ex) {
|
|
||||||
logger.error("IP-Address is unknown to us", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addresses.isEmpty()) {
|
|
||||||
return HttpsURLConnection.getDefaultSSLSocketFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BalancedSSLFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), addresses);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
|
|||||||
if (success) {
|
if (success) {
|
||||||
//update only on success to prevent corrupt data
|
//update only on success to prevent corrupt data
|
||||||
if (playerProfile != null) {
|
if (playerProfile != null) {
|
||||||
playerProfile.setUuid(session.getUuid());
|
playerProfile.setUUID(session.getUuid());
|
||||||
playerProfile.setPremium(true);
|
playerProfile.setPremium(true);
|
||||||
storage.save(playerProfile);
|
storage.save(playerProfile);
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
|
|||||||
}
|
}
|
||||||
} else if (playerProfile != null) {
|
} else if (playerProfile != null) {
|
||||||
//cracked player
|
//cracked player
|
||||||
playerProfile.setUuid(null);
|
playerProfile.setUUID(null);
|
||||||
playerProfile.setPremium(false);
|
playerProfile.setPremium(false);
|
||||||
storage.save(playerProfile);
|
storage.save(playerProfile);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user