Saving changes, password results now in enum

This commit is contained in:
samo_lego 2020-11-07 17:55:21 +01:00
parent d198a67346
commit 48dd9ce00b
8 changed files with 53 additions and 93 deletions

View File

@ -71,7 +71,7 @@ public class AccountCommand {
// Different thread to avoid lag spikes // Different thread to avoid lag spikes
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
if (AuthHelper.checkPassword(((PlayerAuth) player).getFakeUuid(), pass.toCharArray()) == 1) { if (AuthHelper.checkPassword(((PlayerAuth) player).getFakeUuid(), pass.toCharArray()) == AuthHelper.PasswordOptions.CORRECT) {
DB.deleteUserData(((PlayerAuth) player).getFakeUuid()); DB.deleteUserData(((PlayerAuth) player).getFakeUuid());
player.sendMessage(new LiteralText(config.lang.accountDeleted), false); player.sendMessage(new LiteralText(config.lang.accountDeleted), false);
((PlayerAuth) player).setAuthenticated(false); ((PlayerAuth) player).setAuthenticated(false);
@ -99,7 +99,7 @@ public class AccountCommand {
} }
// Different thread to avoid lag spikes // Different thread to avoid lag spikes
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
if (AuthHelper.checkPassword(((PlayerAuth) player).getFakeUuid(), oldPass.toCharArray()) == 1) { if (AuthHelper.checkPassword(((PlayerAuth) player).getFakeUuid(), oldPass.toCharArray()) == AuthHelper.PasswordOptions.CORRECT) {
if (newPass.length() < config.main.minPasswordChars) { if (newPass.length() < config.main.minPasswordChars) {
player.sendMessage(new LiteralText( player.sendMessage(new LiteralText(
String.format(config.lang.minPasswordChars, config.main.minPasswordChars) String.format(config.lang.minPasswordChars, config.main.minPasswordChars)

View File

@ -9,7 +9,6 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.samo_lego.simpleauth.SimpleAuth;
import org.samo_lego.simpleauth.storage.AuthConfig; import org.samo_lego.simpleauth.storage.AuthConfig;
import org.samo_lego.simpleauth.storage.PlayerCache; import org.samo_lego.simpleauth.storage.PlayerCache;
import org.samo_lego.simpleauth.utils.AuthHelper; import org.samo_lego.simpleauth.utils.AuthHelper;
@ -93,7 +92,7 @@ public class AuthCommand {
.then(literal("update") .then(literal("update")
.then(argument("uuid", word()) .then(argument("uuid", word())
.then(argument("password", word()) .then(argument("password", word())
.executes( ctx -> updatePass( .executes( ctx -> updatePassword(
ctx.getSource(), ctx.getSource(),
getString(ctx, "uuid"), getString(ctx, "uuid"),
getString(ctx, "password") getString(ctx, "password")
@ -188,7 +187,7 @@ public class AuthCommand {
Entity sender = source.getEntity(); Entity sender = source.getEntity();
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
DB.deleteUserData(uuid); DB.deleteUserData(uuid);
SimpleAuth.playerCacheMap.put(uuid, new PlayerCache(null)); playerCacheMap.put(uuid, null);
}); });
if(sender != null) if(sender != null)
@ -216,12 +215,11 @@ public class AuthCommand {
playerCache = playerCacheMap.get(uuid); playerCache = playerCacheMap.get(uuid);
} }
else { else {
playerCache = new PlayerCache(null); playerCache = PlayerCache.fromJson(null, uuid);
} }
playerCacheMap.put(uuid, playerCache); playerCacheMap.put(uuid, playerCache);
playerCacheMap.get(uuid).password = AuthHelper.hashPassword(password.toCharArray()); playerCacheMap.get(uuid).password = AuthHelper.hashPassword(password.toCharArray());
playerCacheMap.get(uuid).isRegistered = true;
if (sender != null) if (sender != null)
((PlayerEntity) sender).sendMessage(new LiteralText(config.lang.userdataUpdated), false); ((PlayerEntity) sender).sendMessage(new LiteralText(config.lang.userdataUpdated), false);
@ -239,7 +237,7 @@ public class AuthCommand {
* @param password new password for the player * @param password new password for the player
* @return 0 * @return 0
*/ */
private static int updatePass(ServerCommandSource source, String uuid, String password) { private static int updatePassword(ServerCommandSource source, String uuid, String password) {
// Getting the player who send the command // Getting the player who send the command
Entity sender = source.getEntity(); Entity sender = source.getEntity();
@ -249,11 +247,11 @@ public class AuthCommand {
playerCache = playerCacheMap.get(uuid); playerCache = playerCacheMap.get(uuid);
} }
else { else {
playerCache = new PlayerCache(null); playerCache = PlayerCache.fromJson(null, uuid);
} }
playerCacheMap.put(uuid, playerCache); playerCacheMap.put(uuid, playerCache);
if(!playerCacheMap.get(uuid).isRegistered) { if(!playerCacheMap.get(uuid).password.isEmpty()) {
if (sender != null) if (sender != null)
((PlayerEntity) sender).sendMessage(new LiteralText(config.lang.userNotRegistered), false); ((PlayerEntity) sender).sendMessage(new LiteralText(config.lang.userNotRegistered), false);
else else

View File

@ -40,18 +40,18 @@ public class LoginCommand {
// Putting rest of the command in different thread to avoid lag spikes // Putting rest of the command in different thread to avoid lag spikes
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
int maxLoginTries = config.main.maxLoginTries; int maxLoginTries = config.main.maxLoginTries;
int passwordResult = AuthHelper.checkPassword(uuid, pass.toCharArray()); AuthHelper.PasswordOptions passwordResult = AuthHelper.checkPassword(uuid, pass.toCharArray());
if(playerCacheMap.get(uuid).loginTries >= maxLoginTries && maxLoginTries != -1) { if(playerCacheMap.get(uuid).loginTries >= maxLoginTries && maxLoginTries != -1) {
player.networkHandler.disconnect(new LiteralText(config.lang.loginTriesExceeded)); player.networkHandler.disconnect(new LiteralText(config.lang.loginTriesExceeded));
return; return;
} }
else if(passwordResult == 1) { else if(passwordResult == AuthHelper.PasswordOptions.CORRECT) {
player.sendMessage(new LiteralText(config.lang.successfullyAuthenticated), false); player.sendMessage(new LiteralText(config.lang.successfullyAuthenticated), false);
((PlayerAuth) player).setAuthenticated(true); ((PlayerAuth) player).setAuthenticated(true);
return; return;
} }
else if(passwordResult == -1) { else if(passwordResult == AuthHelper.PasswordOptions.NOT_REGISTERED) {
player.sendMessage(new LiteralText(config.lang.registerRequired), false); player.sendMessage(new LiteralText(config.lang.registerRequired), false);
return; return;
} }

View File

@ -63,12 +63,11 @@ public class RegisterCommand {
} }
PlayerCache playerCache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid()); PlayerCache playerCache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid());
if (!playerCache.isRegistered) { if (playerCache.password.isEmpty()) {
((PlayerAuth) player).setAuthenticated(true); ((PlayerAuth) player).setAuthenticated(true);
player.sendMessage(new LiteralText(config.lang.registerSuccess), false); player.sendMessage(new LiteralText(config.lang.registerSuccess), false);
playerCache.password = hashPassword(pass1.toCharArray()); playerCache.password = hashPassword(pass1.toCharArray());
playerCache.isRegistered = true;
return; return;
} }
player.sendMessage(new LiteralText(config.lang.alreadyRegistered), false); player.sendMessage(new LiteralText(config.lang.alreadyRegistered), false);

View File

@ -11,7 +11,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey; import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.samo_lego.simpleauth.SimpleAuth;
import org.samo_lego.simpleauth.storage.PlayerCache; import org.samo_lego.simpleauth.storage.PlayerCache;
import org.samo_lego.simpleauth.utils.PlayerAuth; import org.samo_lego.simpleauth.utils.PlayerAuth;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@ -92,14 +91,13 @@ public class MixinServerPlayerEntity implements PlayerAuth {
public String getFakeUuid() { public String getFakeUuid() {
// If server is in online mode online-mode UUIDs should be used // If server is in online mode online-mode UUIDs should be used
assert server != null; assert server != null;
if(server.isOnlineMode() && this.isUsingMojangAccount()) if(server.isOnlineMode() && this.isUsingMojangAccount() && !config.experimental.forceoOfflineUuids)
return player.getUuidAsString(); return player.getUuidAsString();
/* /*
Lower case is used for Player and PlAyEr to get same UUID (for password storing) Lower case is used for Player and PlAyEr to get same UUID (for password storing)
Mimicking Mojang behaviour, where players cannot set their name to Mimicking Mojang behaviour, where players cannot set their name to
ExAmple if Example is already taken. ExAmple if Example is already taken.
*/ */
// Getting player+s name via GameProfile, in order to be compatible with Drogtor mod
String playername = player.getGameProfile().getName().toLowerCase(); String playername = player.getGameProfile().getName().toLowerCase();
return PlayerEntity.getOfflinePlayerUuid(playername).toString(); return PlayerEntity.getOfflinePlayerUuid(playername).toString();
@ -116,7 +114,7 @@ public class MixinServerPlayerEntity implements PlayerAuth {
if(!playerCacheMap.containsKey(this.getFakeUuid())) { if(!playerCacheMap.containsKey(this.getFakeUuid())) {
// First join // First join
playerCache = new PlayerCache(this.getFakeUuid(), player); playerCache = PlayerCache.fromJson(player, this.getFakeUuid());
playerCacheMap.put(this.getFakeUuid(), playerCache); playerCacheMap.put(this.getFakeUuid(), playerCache);
} }
else { else {
@ -157,12 +155,12 @@ public class MixinServerPlayerEntity implements PlayerAuth {
@Override @Override
public Text getAuthMessage() { public Text getAuthMessage() {
final PlayerCache cache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid()); final PlayerCache cache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid());
if(SimpleAuth.config.main.enableGlobalPassword || cache.isRegistered) if(!config.main.enableGlobalPassword && cache.password.isEmpty())
return new LiteralText( return new LiteralText(
SimpleAuth.config.lang.notAuthenticated + "\n" + SimpleAuth.config.lang.loginRequired config.lang.notAuthenticated+ "\n" + config.lang.registerRequired
); );
return new LiteralText( return new LiteralText(
SimpleAuth.config.lang.notAuthenticated+ "\n" + SimpleAuth.config.lang.registerRequired config.lang.notAuthenticated + "\n" + config.lang.loginRequired
); );
} }

View File

@ -1,7 +1,8 @@
package org.samo_lego.simpleauth.storage; package org.samo_lego.simpleauth.storage;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
@ -9,6 +10,7 @@ import net.minecraft.util.math.Vec3d;
import java.util.Objects; import java.util.Objects;
import static org.samo_lego.simpleauth.SimpleAuth.DB;
import static org.samo_lego.simpleauth.SimpleAuth.config; import static org.samo_lego.simpleauth.SimpleAuth.config;
import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo;
@ -16,37 +18,37 @@ import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo;
* Class used for storing the non-authenticated player's cache * Class used for storing the non-authenticated player's cache
*/ */
public class PlayerCache { public class PlayerCache {
/**
* Whether player is registered.
*/
public boolean isRegistered;
/** /**
* Whether player is authenticated. * Whether player is authenticated.
* Used for {@link org.samo_lego.simpleauth.event.AuthEventHandler#onPlayerJoin(ServerPlayerEntity) session validation}. * Used for {@link org.samo_lego.simpleauth.event.AuthEventHandler#onPlayerJoin(ServerPlayerEntity) session validation}.
*/ */
public boolean isAuthenticated; @Expose
public boolean isAuthenticated = false;
/** /**
* Hashed password of player. * Hashed password of player.
*/ */
public String password; @Expose
public String password = "";
/** /**
* Stores how many times player has tried to login. * Stores how many times player has tried to login.
*/ */
public int loginTries; public int loginTries = 0;
/** /**
* Last recorded IP of player. * Last recorded IP of player.
* Used for {@link org.samo_lego.simpleauth.event.AuthEventHandler#onPlayerJoin(ServerPlayerEntity) sessions}. * Used for {@link org.samo_lego.simpleauth.event.AuthEventHandler#onPlayerJoin(ServerPlayerEntity) sessions}.
*/ */
@Expose
public String lastIp; public String lastIp;
/** /**
* Time until session is valid. * Time until session is valid.
*/ */
@Expose
public long validUntil; public long validUntil;
/** /**
* Player stats before de-authentication. * Player stats before de-authentication.
*/ */
public boolean wasInPortal; public boolean wasInPortal = false;
/** /**
* Last recorded position before de-authentication. * Last recorded position before de-authentication.
@ -61,7 +63,9 @@ public class PlayerCache {
public final PlayerCache.LastLocation lastLocation = new PlayerCache.LastLocation(); public final PlayerCache.LastLocation lastLocation = new PlayerCache.LastLocation();
private static final Gson gson = new Gson(); private static final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
/** /**
* Creates an empty cache for player (when player doesn't exist in DB). * Creates an empty cache for player (when player doesn't exist in DB).
@ -69,11 +73,6 @@ public class PlayerCache {
* @param player player to create cache for * @param player player to create cache for
*/ */
public PlayerCache(ServerPlayerEntity player) { public PlayerCache(ServerPlayerEntity player) {
if(config.experimental.debugMode)
logInfo("Creating cache for " + Objects.requireNonNull(player).getName());
this.isAuthenticated = false;
this.loginTries = 0;
if(player != null) { if(player != null) {
this.lastIp = player.getIp(); this.lastIp = player.getIp();
@ -85,57 +84,24 @@ public class PlayerCache {
this.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL); this.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL);
} }
else {
this.wasInPortal = false;
}
this.isRegistered = false;
this.password = "";
if(config.experimental.debugMode)
logInfo("New player cache created.");
} }
public static PlayerCache fromJson(ServerPlayerEntity player, String json) { public static PlayerCache fromJson(ServerPlayerEntity player, String fakeUuid) {
if(config.experimental.debugMode) if(config.experimental.debugMode)
logInfo("Creating cache for " + Objects.requireNonNull(player).getName()); logInfo("Creating cache for " + Objects.requireNonNull(player).getGameProfile().getName());
// Parsing data from DB PlayerCache playerCache = new PlayerCache(player);;
PlayerCache playerCache = gson.fromJson(json, PlayerCache.class);
playerCache.loginTries = 0; String json = DB.getUserData(fakeUuid);
playerCache.isAuthenticated = false; if(!json.isEmpty()) {
// Parsing data from DB
if(playerCache.password != null && !playerCache.password.isEmpty()) { playerCache = gson.fromJson(json, PlayerCache.class);
playerCache.isRegistered = true;
}
else {
// Not registered
playerCache.isRegistered = false;
playerCache.password = "";
}
if(player != null) {
playerCache.lastIp = player.getIp();
playerCache.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL);
// Setting position cache
playerCache.lastLocation.dimension = player.getServerWorld();
playerCache.lastLocation.position = player.getPos();
playerCache.lastLocation.yaw = player.yaw;
playerCache.lastLocation.pitch = player.pitch;
}
else {
playerCache.wasInPortal = false;
} }
return playerCache; return playerCache;
} }
public JsonObject toJson() { public String toJson() {
JsonObject cacheJson = new JsonObject(); return gson.toJson(this);
cacheJson.addProperty("password", this.password);
return cacheJson;
} }
} }

View File

@ -1,6 +1,5 @@
package org.samo_lego.simpleauth.storage.database; package org.samo_lego.simpleauth.storage.database;
import com.google.gson.JsonObject;
import org.iq80.leveldb.DB; import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBException; import org.iq80.leveldb.DBException;
import org.iq80.leveldb.Options; import org.iq80.leveldb.Options;
@ -140,8 +139,8 @@ public class LevelDB {
WriteBatch batch = levelDBStore.createWriteBatch(); WriteBatch batch = levelDBStore.createWriteBatch();
// Updating player data. // Updating player data.
playerCacheMap.forEach((uuid, playerCache) -> { playerCacheMap.forEach((uuid, playerCache) -> {
JsonObject data = playerCache.toJson(); String data = playerCache.toJson();
batch.put(bytes("UUID:" + uuid), bytes("data:" + data.toString())); batch.put(bytes("UUID:" + uuid), bytes("data:" + data));
}); });
try { try {
// Writing and closing batch // Writing and closing batch

View File

@ -14,24 +14,18 @@ public class AuthHelper {
* @param password password that needs to be checked * @param password password that needs to be checked
* @return 1 for pass, 0 if password is false, -1 if user is not yet registered * @return 1 for pass, 0 if password is false, -1 if user is not yet registered
*/ */
public static int checkPassword(String uuid, char[] password) { public static PasswordOptions checkPassword(String uuid, char[] password) {
if(config.main.enableGlobalPassword) { if(config.main.enableGlobalPassword) {
// We have global password enabled // We have global password enabled
return verifyPassword(password, config.main.globalPassword) ? 1 : 0; return verifyPassword(password, config.main.globalPassword) ? PasswordOptions.CORRECT : PasswordOptions.WRONG;
} }
else { else {
String hashed; String hashed = playerCacheMap.get(uuid).password;
// Password from cache
if(playerCacheMap.get(uuid).isRegistered)
hashed = playerCacheMap.get(uuid).password;
else
return -1;
if(hashed.isEmpty()) if(hashed.isEmpty())
return -1; // User is not yet registered return PasswordOptions.NOT_REGISTERED;
// Verify password // Verify password
return verifyPassword(password, hashed) ? 1 : 0; return verifyPassword(password, hashed) ? PasswordOptions.CORRECT : PasswordOptions.WRONG;
} }
} }
@ -54,4 +48,10 @@ public class AuthHelper {
else else
return HasherArgon2.verify(pass, hashed); return HasherArgon2.verify(pass, hashed);
} }
public enum PasswordOptions {
CORRECT,
WRONG,
NOT_REGISTERED
}
} }