mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-07-29 18:27:36 +02:00
Add HTTP-proxies support
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
### 1.10
|
||||
|
||||
* Add support for HTTP proxies
|
||||
* Set the fake offline UUID on lowest priority (-> as soon as possible)
|
||||
* Remove bungee chatcolor for Bukkit to support KCauldron
|
||||
* Minor cleanup using inspections + Https
|
||||
|
@ -41,7 +41,7 @@ public class EncryptionUtil {
|
||||
|
||||
public static byte[] getServerIdHash(String serverId, Key publicKey, Key secretKey) {
|
||||
return digestOperation("SHA-1"
|
||||
, new byte[][]{serverId.getBytes(Charsets.ISO_8859_1), secretKey.getEncoded(), publicKey.getEncoded()});
|
||||
, serverId.getBytes(Charsets.ISO_8859_1), secretKey.getEncoded(), publicKey.getEncoded());
|
||||
}
|
||||
|
||||
private static byte[] digestOperation(String algo, byte[]... content) {
|
||||
|
@ -195,7 +195,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
@Override
|
||||
public Map<String, Object> loadYamlFile(Reader reader) {
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(reader);
|
||||
return config.getValues(false);
|
||||
return config.getValues(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -215,7 +215,8 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
}
|
||||
|
||||
@Override
|
||||
public MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests) {
|
||||
return new MojangApiBukkit(logger, addresses, requests);
|
||||
public MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests
|
||||
, Map<String, Integer> proxies) {
|
||||
return new MojangApiBukkit(logger, addresses, requests, proxies);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -20,8 +21,8 @@ public class MojangApiBukkit extends MojangApiConnector {
|
||||
//mojang api check to prove a player is logged in minecraft and made a join server request
|
||||
private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?";
|
||||
|
||||
public MojangApiBukkit(Logger logger, List<String> localAddresses, int rateLimit) {
|
||||
super(logger, localAddresses, rateLimit);
|
||||
public MojangApiBukkit(Logger logger, List<String> localAddresses, int rateLimit, Map<String, Integer> proxies) {
|
||||
super(logger, localAddresses, rateLimit, proxies);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -8,17 +8,12 @@ import com.github.games647.fastlogin.core.shared.MojangApiConnector;
|
||||
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -70,28 +65,6 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
|
||||
}
|
||||
}
|
||||
|
||||
public void saveDefaultFile(String fileName) {
|
||||
if (!getDataFolder().exists()) {
|
||||
getDataFolder().mkdir();
|
||||
}
|
||||
|
||||
File configFile = new File(getDataFolder(), fileName);
|
||||
if (!configFile.exists()) {
|
||||
InputStream in = getResourceAsStream(fileName);
|
||||
try {
|
||||
Files.copy(in, configFile.toPath());
|
||||
} catch (IOException ioExc) {
|
||||
getLogger().log(Level.SEVERE, "Error saving default " + fileName, ioExc);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
getLogger().log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> getCore() {
|
||||
return core;
|
||||
}
|
||||
@ -139,7 +112,8 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
|
||||
}
|
||||
|
||||
@Override
|
||||
public MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests) {
|
||||
return new MojangApiBungee(logger, addresses, requests);
|
||||
public MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests
|
||||
, Map<String, Integer> proxies) {
|
||||
return new MojangApiBungee(logger, addresses, requests, proxies);
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,15 @@ import com.github.games647.fastlogin.core.shared.LoginSession;
|
||||
import com.github.games647.fastlogin.core.shared.MojangApiConnector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
|
||||
public class MojangApiBungee extends MojangApiConnector {
|
||||
|
||||
public MojangApiBungee(Logger logger, List<String> localAddresses, int rateLimit) {
|
||||
super(logger, localAddresses, rateLimit);
|
||||
public MojangApiBungee(Logger logger, List<String> localAddresses, int rateLimit, Map<String, Integer> proxies) {
|
||||
super(logger, localAddresses, rateLimit, proxies);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,41 +28,39 @@ public class AuthStorage {
|
||||
, String user, String pass, boolean useSSL) {
|
||||
this.core = core;
|
||||
|
||||
HikariConfig databaseConfig = new HikariConfig();
|
||||
databaseConfig.setUsername(user);
|
||||
databaseConfig.setPassword(pass);
|
||||
databaseConfig.setDriverClassName(driver);
|
||||
HikariConfig config = new HikariConfig();
|
||||
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));
|
||||
databaseConfig.setDataSourceProperties(properties);
|
||||
|
||||
ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder()
|
||||
.setNameFormat(core.getPlugin().getName() + " Database Pool Thread #%1$d")
|
||||
//Hikari create daemons by default
|
||||
.setDaemon(true);
|
||||
config.setDataSourceProperties(properties);
|
||||
|
||||
ThreadFactory platformThreadFactory = core.getPlugin().getThreadFactory();
|
||||
if (platformThreadFactory != null) {
|
||||
threadFactoryBuilder.setThreadFactory(platformThreadFactory);
|
||||
config.setThreadFactory(new ThreadFactoryBuilder()
|
||||
.setNameFormat(core.getPlugin().getName() + " Database Pool Thread #%1$d")
|
||||
//Hikari create daemons by default
|
||||
.setDaemon(true)
|
||||
.setThreadFactory(platformThreadFactory)
|
||||
.build());
|
||||
}
|
||||
|
||||
databaseConfig.setThreadFactory(threadFactoryBuilder.build());
|
||||
|
||||
databasePath = databasePath.replace("{pluginDir}", core.getPlugin().getDataFolder().getAbsolutePath());
|
||||
|
||||
String jdbcUrl = "jdbc:";
|
||||
if (driver.contains("sqlite")) {
|
||||
jdbcUrl += "sqlite" + "://" + databasePath;
|
||||
databaseConfig.setConnectionTestQuery("SELECT 1");
|
||||
config.setConnectionTestQuery("SELECT 1");
|
||||
} else {
|
||||
jdbcUrl += "mysql" + "://" + host + ':' + port + '/' + databasePath;
|
||||
}
|
||||
|
||||
databaseConfig.setJdbcUrl(jdbcUrl);
|
||||
this.dataSource = new HikariDataSource(databaseConfig);
|
||||
config.setJdbcUrl(jdbcUrl);
|
||||
this.dataSource = new HikariDataSource(config);
|
||||
}
|
||||
|
||||
public DataSource getDataSource() {
|
||||
|
@ -41,13 +41,13 @@ public class BalancedSSLFactory extends SSLSocketFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
|
||||
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, UnknownHostException {
|
||||
throws IOException {
|
||||
//default
|
||||
return oldFactory.createSocket(host, port, localAddress, localPort);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @param <P> Player class
|
||||
@ -126,7 +127,12 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
|
||||
List<String> ipAddresses = sharedConfig.get("ip-addresses");
|
||||
int requestLimit = sharedConfig.get("mojang-request-limit");
|
||||
this.apiConnector = plugin.makeApiConnector(plugin.getLogger(), ipAddresses, requestLimit);
|
||||
List<String> proxyList = sharedConfig.get("proxies");
|
||||
Map<String, Integer> proxies = proxyList.stream()
|
||||
.collect(Collectors
|
||||
.toMap(line -> line.split(":")[0], line -> Integer.parseInt(line.split(":")[1])));
|
||||
|
||||
this.apiConnector = plugin.makeApiConnector(plugin.getLogger(), ipAddresses, requestLimit, proxies);
|
||||
}
|
||||
|
||||
public MojangApiConnector getApiConnector() {
|
||||
@ -189,7 +195,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
|
||||
try {
|
||||
if (sqlite && importPlugin == ImportPlugin.AUTO_IN) {
|
||||
//load sqlite driver
|
||||
//load SQLite driver
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
|
||||
String jdbcUrl = "jdbc:sqlite:" + AutoInImporter.getSQLitePath();
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.github.games647.fastlogin.core.shared;
|
||||
|
||||
import com.github.games647.fastlogin.core.BalancedSSLFactory;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@ -8,9 +10,16 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.Proxy.Type;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@ -33,9 +42,10 @@ public abstract class MojangApiConnector {
|
||||
|
||||
private static final int RATE_LIMIT_CODE = 429;
|
||||
|
||||
//compile the pattern only on plugin enable -> and this have to be threadsafe
|
||||
private final Pattern playernameMatcher = Pattern.compile(VALID_PLAYERNAME);
|
||||
//compile the pattern only on plugin enable -> and this have to be thread-safe
|
||||
private final Pattern nameMatcher = Pattern.compile(VALID_PLAYERNAME);
|
||||
|
||||
private final Iterator<Proxy> proxies;
|
||||
private final ConcurrentMap<Object, Object> requests = FastLoginCore.buildCache(10, -1);
|
||||
private final BalancedSSLFactory sslFactory;
|
||||
private final int rateLimit;
|
||||
@ -43,7 +53,8 @@ public abstract class MojangApiConnector {
|
||||
|
||||
protected final Logger logger;
|
||||
|
||||
public MojangApiConnector(Logger logger, Collection<String> localAddresses, int rateLimit) {
|
||||
public MojangApiConnector(Logger logger, Collection<String> localAddresses, int rateLimit
|
||||
, Map<String, Integer> proxies) {
|
||||
this.logger = logger;
|
||||
|
||||
if (rateLimit > 600) {
|
||||
@ -72,26 +83,37 @@ public abstract class MojangApiConnector {
|
||||
|
||||
this.sslFactory = new BalancedSSLFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), addresses);
|
||||
}
|
||||
|
||||
List<Proxy> proxyBuilder = Lists.newArrayList();
|
||||
for (Entry<String, Integer> proxy : proxies.entrySet()) {
|
||||
proxyBuilder.add(new Proxy(Type.HTTP, new InetSocketAddress(proxy.getKey(), proxy.getValue())));
|
||||
}
|
||||
|
||||
this.proxies = Iterables.cycle(proxyBuilder).iterator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param playerName
|
||||
* @return null on non-premium
|
||||
*/
|
||||
public UUID getPremiumUUID(String playerName) {
|
||||
//check if it's a valid playername
|
||||
if (playernameMatcher.matcher(playerName).matches()) {
|
||||
// only make a API call if the name is valid existing mojang account
|
||||
|
||||
if (requests.size() >= rateLimit || System.currentTimeMillis() - lastRateLimit < 1_000 * 60 * 10) {
|
||||
return null;
|
||||
}
|
||||
|
||||
requests.put(new Object(), new Object());
|
||||
|
||||
//check if it's a valid player name
|
||||
if (nameMatcher.matcher(playerName).matches()) {
|
||||
try {
|
||||
HttpsURLConnection connection = getConnection(UUID_LINK + playerName);
|
||||
HttpsURLConnection connection;
|
||||
if (requests.size() >= rateLimit || System.currentTimeMillis() - lastRateLimit < 1_000 * 60 * 10) {
|
||||
synchronized (proxies) {
|
||||
if (proxies.hasNext()) {
|
||||
connection = getConnection(UUID_LINK + playerName, proxies.next());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requests.put(new Object(), new Object());
|
||||
connection = getConnection(UUID_LINK + playerName);
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line = reader.readLine();
|
||||
@ -101,13 +123,14 @@ public abstract class MojangApiConnector {
|
||||
} else if (connection.getResponseCode() == RATE_LIMIT_CODE) {
|
||||
logger.info("RATE_LIMIT REACHED");
|
||||
lastRateLimit = System.currentTimeMillis();
|
||||
return null;
|
||||
if (!connection.usingProxy()) {
|
||||
return getPremiumUUID(playerName);
|
||||
}
|
||||
}
|
||||
//204 - no content for not found
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Failed to check if player has a paid account", ex);
|
||||
}
|
||||
//this connection doesn't need to be closed. So can make use of keep alive in java
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -117,18 +140,23 @@ public abstract class MojangApiConnector {
|
||||
|
||||
protected abstract String getUUIDFromJson(String json);
|
||||
|
||||
protected HttpsURLConnection getConnection(String url) throws IOException {
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
|
||||
protected HttpsURLConnection getConnection(String url, Proxy proxy) throws IOException {
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(proxy);
|
||||
connection.setConnectTimeout(TIMEOUT);
|
||||
connection.setReadTimeout(2 * TIMEOUT);
|
||||
//the new Mojang API just uses json as response
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("User-Agent", USER_AGENT);
|
||||
|
||||
//this connection doesn't need to be closed. So can make use of keep alive in java
|
||||
if (sslFactory != null) {
|
||||
connection.setSSLSocketFactory(sslFactory);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getConnection(String url) throws IOException {
|
||||
return getConnection(url, Proxy.NO_PROXY);
|
||||
}
|
||||
}
|
||||
|
@ -23,5 +23,6 @@ public interface PlatformPlugin<C> {
|
||||
|
||||
String translateColorCodes(char colorChar, String rawMessage);
|
||||
|
||||
MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests);
|
||||
MojangApiConnector makeApiConnector(Logger logger, List<String> addresses, int requests
|
||||
, Map<String, Integer> proxies);
|
||||
}
|
||||
|
@ -176,3 +176,12 @@ database: '{pluginDir}/FastLogin.db'
|
||||
# It's strongly recommended to enable SSL and setup a SSL certificate if the MySQL server isn't running on the same
|
||||
# machine
|
||||
#useSSL: false
|
||||
|
||||
# HTTP proxies for connecting to the Mojang servers in order to check if the username of a player is premium.
|
||||
# This is a workaround to prevent rate-limiting by Mojang. These proxies will only be used once your server hit
|
||||
# the rate-limit or the custom value above.
|
||||
# Please make sure you use reliable proxies.
|
||||
proxies:
|
||||
# 'IP:Port' or 'Domain:Port'
|
||||
# - 'xyz.com:1337'
|
||||
# - 'test.com:5131'
|
||||
|
Reference in New Issue
Block a user