Skip to content

Commit

Permalink
Fix all the issues
Browse files Browse the repository at this point in the history
Read the last release post
  • Loading branch information
were491 authored Feb 6, 2022
1 parent 75101fa commit 4a1ff63
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 31 deletions.
10 changes: 10 additions & 0 deletions src/main/java/xyz/nikitacartes/easyauth/EasyAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static xyz.nikitacartes.easyauth.utils.EasyLogger.logInfo;
import static xyz.nikitacartes.easyauth.EasyAuth.RESET_LOGIN_THREAD;
import static xyz.nikitacartes.easyauth.utils.EasyLogger.logError;

public class EasyAuth implements ModInitializer {
Expand All @@ -34,6 +36,11 @@ public class EasyAuth implements ModInitializer {

public static final ExecutorService THREADPOOL = Executors.newCachedThreadPool();

/**
* Used to reset login attempts with a delay and (in the future) other small tasks.
*/
public static final ScheduledThreadPoolExecutor RESET_LOGIN_THREAD = new ScheduledThreadPoolExecutor(1);

/**
* HashMap of players that have joined the server.
* It's cleared on server stop in order to save some interactions with database during runtime.
Expand Down Expand Up @@ -77,6 +84,8 @@ public static void init(Path gameDir) {
throw new RuntimeException("[EasyAuth] Error creating directory!");
// Loading config
config = AuthConfig.load(new File(gameDirectory + "/mods/EasyAuth/config.json"));
// Allow the thread to shutdown properly when server is closed by canceling every scheduled task.
RESET_LOGIN_THREAD.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
// Connecting to db
DB.openConnection();
}
Expand All @@ -98,6 +107,7 @@ public static void stop() {
logError(e.getMessage());
THREADPOOL.shutdownNow();
}
RESET_LOGIN_THREAD.shutdown();

// Closing DB connection
DB.close();
Expand Down
29 changes: 6 additions & 23 deletions src/main/java/xyz/nikitacartes/easyauth/commands/LoginCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@
import static net.minecraft.server.command.CommandManager.literal;
import static xyz.nikitacartes.easyauth.EasyAuth.*;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class LoginCommand {

// To reset the login attempts...
public static final ScheduledExecutorService RESET_LOGIN_THREAD = Executors.newScheduledThreadPool(1);

public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
LiteralCommandNode<ServerCommandSource> node = registerLogin(dispatcher); // Registering the "/login" command
if (config.experimental.enableAliases) {
Expand Down Expand Up @@ -57,10 +52,6 @@ private static int login(ServerCommandSource source, String pass) throws Command
return 0;
}

// ++ the login tries. Maybe it's more threadsafe here than in the thread pool?
// But if not, you could save the calls to set this back to 0.
playerCacheMap.get(uuid).loginTries++;

// Putting rest of the command in different thread to avoid lag spikes
THREADPOOL.submit(() -> {
int maxLoginTries = config.main.maxLoginTries;
Expand All @@ -69,38 +60,30 @@ private static int login(ServerCommandSource source, String pass) throws Command
if (passwordResult == AuthHelper.PasswordOptions.CORRECT) {
player.sendMessage(TranslationHelper.getSuccessfullyAuthenticated(), false);
((PlayerAuth) player).setAuthenticated(true);

// Reset their login tries
playerCacheMap.get(uuid).loginTries = 0;

playerCacheMap.get(uuid).resetLoginTries();
// player.getServer().getPlayerManager().sendToAll(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, player));
return;
} else if (passwordResult == AuthHelper.PasswordOptions.NOT_REGISTERED) {
player.sendMessage(TranslationHelper.getRegisterRequired(), false);

// Reset their login tries
playerCacheMap.get(uuid).loginTries = 0;

return;
}
// Kicking the player out
else if (maxLoginTries == 1) {
// Reset their login tries
playerCacheMap.get(uuid).loginTries = 0;

else if (maxLoginTries == 1) {
player.networkHandler.disconnect(TranslationHelper.getWrongPassword());
return;
} else if(playerCacheMap.get(uuid).loginTries == maxLoginTries) {
} else if (playerCacheMap.get(uuid).getLoginTries() >= maxLoginTries - 1) {
player.networkHandler.disconnect(TranslationHelper.getLoginTriesExceeded());

// Reset their login try counter after the amount of seconds specified in the config.
RESET_LOGIN_THREAD.schedule(() -> {
playerCacheMap.get(uuid).loginTries = 0;
playerCacheMap.get(uuid).resetLoginTries();
}, config.experimental.resetLoginAttemptsTime, TimeUnit.SECONDS);
return;
}
// Sending wrong pass message
player.sendMessage(TranslationHelper.getWrongPassword(), false);
// Increment (failed) login tries. Hopefully this is more thread-safe.
playerCacheMap.get(uuid).incrementLoginTries();
});
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static LiteralText checkCanPlayerJoinServer(GameProfile profile, PlayerMa

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(incomingPlayerUsername);

if ((onlinePlayer != null && !((PlayerAuth) onlinePlayer).canSkipAuth()) && config.experimental.preventAnotherLocationKick) {
// Player needs to be kicked, since there's already a player with that name
// playing on the server
Expand Down Expand Up @@ -97,16 +97,14 @@ public static void onPlayerJoin(ServerPlayerEntity player) {
player.setInvisible(false);
return;
}

// If the player has too many login attempts, kick the player immediately.
if (playerCache.loginTries > config.main.maxLoginTries && config.main.maxLoginTries != -1) {
// If the player has too many login attempts, kick them immediately.
// TODO: Move this to checkCanPlayerJoinServer?
if (playerCache.getLoginTries() >= config.main.maxLoginTries - 1 && config.main.maxLoginTries != -1) {
player.networkHandler.disconnect(TranslationHelper.getLoginTriesExceeded());
return;
}

((PlayerAuth) player).setAuthenticated(false);



// Tries to rescue player from nether portal
if (config.main.tryPortalRescue && player.getBlockStateAtPos().getBlock().equals(Blocks.NETHER_PORTAL)) {
BlockPos pos = player.getBlockPos();
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/xyz/nikitacartes/easyauth/storage/PlayerCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ public class PlayerCache {
public String password = "";
/**
* Stores how many times player has tried to log in.
* This should only be a max of maxLoginTries - 1.
*/
public int loginTries = 0;
private int loginTries = 0;
/**
* Last recorded IP of player.
* Used for {@link AuthEventHandler#onPlayerJoin(ServerPlayerEntity) sessions}.
Expand Down Expand Up @@ -100,6 +101,9 @@ public static PlayerCache fromJson(ServerPlayerEntity player, String fakeUuid) {

// playerCache.wasInPortal = player.getBlockStateAtPos().getBlock().equals(Blocks.NETHER_PORTAL);
playerCache.wasInPortal = false;

// This only happens on the first login after server reset. Reset login attempts just to be safe.
playerCache.resetLoginTries();
}

return playerCache;
Expand All @@ -113,4 +117,15 @@ public static boolean isAuthenticated(String uuid) {
PlayerCache playerCache = playerCacheMap.get(uuid);
return (playerCache != null && playerCache.isAuthenticated);
}

// Hide the actual login tries modifications behind synchronized functions for thread safety.
public synchronized void incrementLoginTries() {
loginTries++;
}
public synchronized void resetLoginTries() {
loginTries = 0;
}
public synchronized int getLoginTries() {
return loginTries;
}
}

0 comments on commit 4a1ff63

Please sign in to comment.