Use Instant for timestamps

This commit is contained in:
games647
2017-10-01 17:11:06 +02:00
parent dce44295d0
commit 105e00b7e8
24 changed files with 122 additions and 101 deletions
@@ -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> {
@@ -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();
+4 -4
View File
@@ -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:
+1 -1
View File
@@ -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