forked from TuxCoding/FastLogin
Use Instant for timestamps
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package com.github.games647.fastlogin.core;
|
||||
|
||||
import com.github.games647.fastlogin.core.shared.FastLoginCore;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
@@ -10,14 +9,24 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.time.Instant;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import static java.sql.Statement.RETURN_GENERATED_KEYS;
|
||||
|
||||
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 (?, ?, ?, ?) ";
|
||||
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;
|
||||
|
||||
@@ -38,22 +47,18 @@ public class AuthStorage {
|
||||
|
||||
ThreadFactory platformThreadFactory = core.getPlugin().getThreadFactory();
|
||||
if (platformThreadFactory != null) {
|
||||
config.setThreadFactory(new ThreadFactoryBuilder()
|
||||
.setNameFormat(core.getPlugin().getName() + " Database Pool Thread #%1$d")
|
||||
//Hikari create daemons by default
|
||||
.setDaemon(true)
|
||||
.setThreadFactory(platformThreadFactory)
|
||||
.build());
|
||||
config.setThreadFactory(platformThreadFactory);
|
||||
}
|
||||
|
||||
databasePath = databasePath.replace("{pluginDir}", core.getPlugin().getDataFolder().getAbsolutePath());
|
||||
String pluginFolder = core.getPlugin().getPluginFolder().toAbsolutePath().toString();
|
||||
databasePath = databasePath.replace("{pluginDir}", pluginFolder);
|
||||
|
||||
String jdbcUrl = "jdbc:";
|
||||
if (driver.contains("sqlite")) {
|
||||
jdbcUrl += "sqlite" + "://" + databasePath;
|
||||
jdbcUrl += "sqlite://" + databasePath;
|
||||
config.setConnectionTestQuery("SELECT 1");
|
||||
} else {
|
||||
jdbcUrl += "mysql" + "://" + host + ':' + port + '/' + databasePath;
|
||||
jdbcUrl += "mysql://" + host + ':' + port + '/' + databasePath;
|
||||
}
|
||||
|
||||
config.setJdbcUrl(jdbcUrl);
|
||||
@@ -84,8 +89,7 @@ public class AuthStorage {
|
||||
|
||||
public PlayerProfile loadProfile(String name) {
|
||||
try (Connection con = dataSource.getConnection();
|
||||
PreparedStatement loadStmt = con.prepareStatement("SELECT * FROM "
|
||||
+ PREMIUM_TABLE + " WHERE Name=? LIMIT 1")) {
|
||||
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_NAME)) {
|
||||
loadStmt.setString(1, name);
|
||||
|
||||
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
||||
@@ -96,7 +100,7 @@ public class AuthStorage {
|
||||
|
||||
boolean premium = resultSet.getBoolean(4);
|
||||
String lastIp = resultSet.getString(5);
|
||||
long lastLogin = resultSet.getTimestamp(6).getTime();
|
||||
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
||||
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
|
||||
} else {
|
||||
return new PlayerProfile(null, name, false, "");
|
||||
@@ -111,8 +115,7 @@ public class AuthStorage {
|
||||
|
||||
public PlayerProfile loadProfile(UUID uuid) {
|
||||
try (Connection con = dataSource.getConnection();
|
||||
PreparedStatement loadStmt = con.prepareStatement("SELECT * FROM "
|
||||
+ PREMIUM_TABLE + " WHERE UUID=? LIMIT 1")) {
|
||||
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_UUID)) {
|
||||
loadStmt.setString(1, uuid.toString().replace("-", ""));
|
||||
|
||||
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
||||
@@ -122,7 +125,7 @@ public class AuthStorage {
|
||||
String name = resultSet.getString(3);
|
||||
boolean premium = resultSet.getBoolean(4);
|
||||
String lastIp = resultSet.getString(5);
|
||||
long lastLogin = resultSet.getTimestamp(6).getTime();
|
||||
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
||||
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
|
||||
}
|
||||
}
|
||||
@@ -138,8 +141,7 @@ public class AuthStorage {
|
||||
UUID uuid = playerProfile.getUuid();
|
||||
|
||||
if (playerProfile.getUserId() == -1) {
|
||||
try (PreparedStatement saveStmt = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE
|
||||
+ " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?) ", Statement.RETURN_GENERATED_KEYS)) {
|
||||
try (PreparedStatement saveStmt = con.prepareStatement(INSERT_PROFILE, RETURN_GENERATED_KEYS)) {
|
||||
if (uuid == null) {
|
||||
saveStmt.setString(1, null);
|
||||
} else {
|
||||
@@ -159,8 +161,7 @@ public class AuthStorage {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (PreparedStatement saveStmt = con.prepareStatement("UPDATE " + PREMIUM_TABLE
|
||||
+ " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=CURRENT_TIMESTAMP WHERE UserID=?")) {
|
||||
try (PreparedStatement saveStmt = con.prepareStatement(UPDATE_PROFILE)) {
|
||||
if (uuid == null) {
|
||||
saveStmt.setString(1, null);
|
||||
} else {
|
||||
|
||||
@@ -136,8 +136,9 @@ public class CompatibleCacheBuilder<K, V> {
|
||||
* <p>
|
||||
* <p>
|
||||
* When {@code size} is zero, elements will be evicted immediately after being loaded into the cache. This has the
|
||||
* same effect as invoking {@link #expireAfterWrite expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
|
||||
* unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
|
||||
* same effect as invoking {@link #expireAfterWrite expireAfterWrite}{@code (0, unit)} or
|
||||
* {@link #expireAfterAccess expireAfterAccess}{@code (0,unit)}.
|
||||
* It can be useful in testing, or to disable caching temporarily without a code change.
|
||||
*
|
||||
* @param size the maximum size of the cache
|
||||
* @return This for chaining
|
||||
@@ -180,7 +181,8 @@ public class CompatibleCacheBuilder<K, V> {
|
||||
* @throws IllegalStateException if a removal listener was already set
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K1 extends K, V1 extends V> CompatibleCacheBuilder<K1, V1> removalListener(RemovalListener<? super K1, ? super V1> listener) {
|
||||
public <K1 extends K, V1 extends V> CompatibleCacheBuilder<K1, V1> removalListener(
|
||||
RemovalListener<? super K1, ? super V1> listener) {
|
||||
builder.removalListener(listener);
|
||||
return (CompatibleCacheBuilder<K1, V1>) this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.games647.fastlogin.core;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerProfile {
|
||||
@@ -11,9 +12,9 @@ public class PlayerProfile {
|
||||
private UUID uuid;
|
||||
private boolean premium;
|
||||
private String lastIp;
|
||||
private long lastLogin;
|
||||
private Instant lastLogin;
|
||||
|
||||
public PlayerProfile(long userId, UUID uuid, String playerName, boolean premium, String lastIp, long lastLogin) {
|
||||
public PlayerProfile(long userId, UUID uuid, String playerName, boolean premium, String lastIp, Instant lastLogin) {
|
||||
this.userId = userId;
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
@@ -23,7 +24,7 @@ public class PlayerProfile {
|
||||
}
|
||||
|
||||
public PlayerProfile(UUID uuid, String playerName, boolean premium, String lastIp) {
|
||||
this(-1, uuid, playerName, premium, lastIp, System.currentTimeMillis());
|
||||
this(-1, uuid, playerName, premium, lastIp, Instant.now());
|
||||
}
|
||||
|
||||
public synchronized String getPlayerName() {
|
||||
@@ -66,11 +67,11 @@ public class PlayerProfile {
|
||||
this.lastIp = lastIp;
|
||||
}
|
||||
|
||||
public synchronized long getLastLogin() {
|
||||
public synchronized Instant getLastLogin() {
|
||||
return lastLogin;
|
||||
}
|
||||
|
||||
public synchronized void setLastLogin(long lastLogin) {
|
||||
public synchronized void setLastLogin(Instant lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ package com.github.games647.fastlogin.core.hooks;
|
||||
/**
|
||||
* Represents a supporting authentication plugin in BungeeCord and Bukkit/Spigot/... servers
|
||||
*
|
||||
* @param <P> either org.bukkit.entity.GameProfile for Bukkit or net.md_5.bungee.api.connection.ProxiedPlayer for BungeeCord
|
||||
* @param <P> either org.bukkit.entity.GameProfile for Bukkit or net.md_5.bungee.api.connection.ProxiedPlayer
|
||||
* for BungeeCord
|
||||
*/
|
||||
public interface AuthPlugin<P> {
|
||||
|
||||
|
||||
+23
-24
@@ -20,6 +20,8 @@ import java.net.Proxy;
|
||||
import java.net.Proxy.Type;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -53,7 +55,7 @@ public class MojangApiConnector {
|
||||
private final SSLSocketFactory sslFactory;
|
||||
private final int rateLimit;
|
||||
|
||||
private long lastRateLimit;
|
||||
private Instant lastRateLimit;
|
||||
|
||||
protected final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||
protected final Logger logger;
|
||||
@@ -72,9 +74,6 @@ public class MojangApiConnector {
|
||||
this.proxies = Iterables.cycle(proxyBuilder).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null on non-premium
|
||||
*/
|
||||
public Optional<UUID> getPremiumUUID(String playerName) {
|
||||
if (!validNameMatcher.matcher(playerName).matches()) {
|
||||
//check if it's a valid player name
|
||||
@@ -83,7 +82,7 @@ public class MojangApiConnector {
|
||||
|
||||
try {
|
||||
HttpsURLConnection connection;
|
||||
if (requests.size() >= rateLimit || System.currentTimeMillis() - lastRateLimit < 1_000 * 60 * 10) {
|
||||
if (requests.size() >= rateLimit || Duration.between(lastRateLimit, Instant.now()).getSeconds() < 60 * 10) {
|
||||
synchronized (proxies) {
|
||||
if (proxies.hasNext()) {
|
||||
connection = getConnection(UUID_LINK + playerName, proxies.next());
|
||||
@@ -103,7 +102,7 @@ public class MojangApiConnector {
|
||||
}
|
||||
} else if (connection.getResponseCode() == RATE_LIMIT_CODE) {
|
||||
logger.info("RATE_LIMIT REACHED");
|
||||
lastRateLimit = System.currentTimeMillis();
|
||||
lastRateLimit = Instant.now();
|
||||
if (!connection.usingProxy()) {
|
||||
return getPremiumUUID(playerName);
|
||||
}
|
||||
@@ -153,25 +152,25 @@ public class MojangApiConnector {
|
||||
}
|
||||
|
||||
private SSLSocketFactory buildAddresses(Logger logger, Collection<String> localAddresses) {
|
||||
if (localAddresses.isEmpty()) {
|
||||
if (!localAddresses.isEmpty()) {
|
||||
return HttpsURLConnection.getDefaultSSLSocketFactory();
|
||||
} else {
|
||||
Set<InetAddress> addresses = Sets.newHashSet();
|
||||
for (String localAddress : localAddresses) {
|
||||
try {
|
||||
InetAddress address = InetAddress.getByName(localAddress);
|
||||
if (!address.isAnyLocalAddress()) {
|
||||
logger.warn("Submitted IP-Address is not local {0}", address);
|
||||
continue;
|
||||
}
|
||||
|
||||
addresses.add(address);
|
||||
} catch (UnknownHostException ex) {
|
||||
logger.error("IP-Address is unknown to us", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return new BalancedSSLFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), addresses);
|
||||
}
|
||||
|
||||
Set<InetAddress> addresses = Sets.newHashSet();
|
||||
for (String localAddress : localAddresses) {
|
||||
try {
|
||||
InetAddress address = InetAddress.getByName(localAddress);
|
||||
if (!address.isAnyLocalAddress()) {
|
||||
logger.warn("Submitted IP-Address is not local {}", address);
|
||||
continue;
|
||||
}
|
||||
|
||||
addresses.add(address);
|
||||
} catch (UnknownHostException ex) {
|
||||
logger.error("IP-Address is unknown to us", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return new BalancedSSLFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), addresses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@ package com.github.games647.fastlogin.core.mojang;
|
||||
|
||||
public class SkinProperties {
|
||||
|
||||
private final String name = "textures";
|
||||
|
||||
private String value;
|
||||
private String signature;
|
||||
|
||||
public String getName() {
|
||||
return "textures";
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -11,18 +11,10 @@ import java.util.UUID;
|
||||
public class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
||||
|
||||
public void write(JsonWriter out, UUID value) throws IOException {
|
||||
out.value(fromUUID(value));
|
||||
out.value(value.toString().replace("-", ""));
|
||||
}
|
||||
|
||||
public UUID read(JsonReader in) throws IOException {
|
||||
return fromString(in.nextString());
|
||||
}
|
||||
|
||||
public static String fromUUID(UUID value) {
|
||||
return value.toString().replace("-", "");
|
||||
}
|
||||
|
||||
public static UUID fromString(String input) {
|
||||
return CommonUtil.parseId(input);
|
||||
return CommonUtil.parseId(in.nextString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
defaults = configProvider.load(defaultStream);
|
||||
}
|
||||
|
||||
File file = new File(plugin.getDataFolder(), fileName);
|
||||
File file = plugin.getPluginFolder().resolve(fileName).toFile();
|
||||
return configProvider.load(file, defaults);
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
||||
}
|
||||
|
||||
public void saveDefaultFile(String fileName) {
|
||||
Path dataFolder = plugin.getDataFolder().toPath();
|
||||
Path dataFolder = plugin.getPluginFolder();
|
||||
|
||||
try {
|
||||
Files.createDirectories(dataFolder);
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.github.games647.fastlogin.core.shared;
|
||||
import com.github.games647.fastlogin.core.mojang.MojangApiConnector;
|
||||
import com.google.common.net.HostAndPort;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
@@ -13,7 +13,7 @@ public interface PlatformPlugin<C> {
|
||||
|
||||
String getName();
|
||||
|
||||
File getDataFolder();
|
||||
Path getPluginFolder();
|
||||
|
||||
Logger getLog();
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ premiumUuid: false
|
||||
# #### Case 1
|
||||
# nameChangeCheck = false ----- autoRegister = false
|
||||
#
|
||||
# GameProfile logins as cracked until the player invoked the command /premium. Then we could override the existing database
|
||||
# record.
|
||||
# GameProfile logins as cracked until the player invoked the command /premium. Then we could override the existing
|
||||
# database record.
|
||||
#
|
||||
# #### Case 2
|
||||
#
|
||||
@@ -128,8 +128,8 @@ premium-warning: true
|
||||
# Once the limit is reached, new players are always logged in as cracked until the rate-limit is expired.
|
||||
# (to the next ten minutes)
|
||||
#
|
||||
# The limit is IP-wide. If you have multiple IPv4-addresses you specify them here. FastLogin will then use it in rotating
|
||||
# order --> 5 different IP-addresses 5 * 600 per 10 minutes
|
||||
# The limit is IP-wide. If you have multiple IPv4-addresses you specify them here. FastLogin will then use it in
|
||||
# rotating order --> 5 different IP-addresses 5 * 600 per 10 minutes
|
||||
# If this list is empty only the default one will be used
|
||||
#
|
||||
# Lists are created like this:
|
||||
|
||||
@@ -86,7 +86,7 @@ invalid-session: '&4Invalid session'
|
||||
# The client sent a malicious packet without a login request packet
|
||||
invalid-requst: '&4Invalid request'
|
||||
|
||||
# Message if the bukkit isn't fully started to inject the packets
|
||||
# Message if the Bukkit isn't fully started to inject the packets
|
||||
not-started: '&cServer is not fully started yet. Please retry'
|
||||
|
||||
# Warning message if a user invoked /premium command
|
||||
|
||||
Reference in New Issue
Block a user