Finalising position protection.
This commit is contained in:
parent
1b0b72afa1
commit
8405680f42
|
@ -1,5 +1,6 @@
|
|||
package org.samo_lego.simpleauth;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||
import net.fabricmc.fabric.api.event.player.*;
|
||||
import net.fabricmc.fabric.api.event.server.ServerStopCallback;
|
||||
|
@ -13,6 +14,7 @@ import net.minecraft.text.Text;
|
|||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.iq80.leveldb.WriteBatch;
|
||||
import org.samo_lego.simpleauth.commands.*;
|
||||
import org.samo_lego.simpleauth.event.AuthEventHandler;
|
||||
import org.samo_lego.simpleauth.event.entity.player.*;
|
||||
|
@ -23,10 +25,12 @@ import org.samo_lego.simpleauth.storage.PlayerCache;
|
|||
import org.samo_lego.simpleauth.storage.SimpleAuthDatabase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static org.iq80.leveldb.impl.Iq80DBFactory.bytes;
|
||||
import static org.samo_lego.simpleauth.utils.CarpetHelper.isPlayerCarpetFake;
|
||||
import static org.samo_lego.simpleauth.utils.UuidConverter.convertUuid;
|
||||
|
||||
|
@ -98,6 +102,32 @@ public class SimpleAuth implements DedicatedServerModInitializer {
|
|||
|
||||
private static void onStopServer() {
|
||||
LOGGER.info("[SimpleAuth] Shutting down SimpleAuth.");
|
||||
|
||||
WriteBatch batch = db.levelDBStore.createWriteBatch();
|
||||
// Writing coords of de-authenticated players to database
|
||||
deauthenticatedUsers.forEach((uuid, playerCache) -> {
|
||||
JsonObject data = new JsonObject();
|
||||
data.addProperty("password", playerCache.password);
|
||||
|
||||
JsonObject lastLocation = new JsonObject();
|
||||
lastLocation.addProperty("dimId", playerCache.lastDimId);
|
||||
lastLocation.addProperty("x", playerCache.lastX);
|
||||
lastLocation.addProperty("y", playerCache.lastY);
|
||||
lastLocation.addProperty("z", playerCache.lastZ);
|
||||
|
||||
data.addProperty("lastLocation", lastLocation.toString());
|
||||
|
||||
batch.put(bytes("UUID:" + uuid), bytes("data:" + data.toString()));
|
||||
});
|
||||
try {
|
||||
// Writing and closing batch
|
||||
db.levelDBStore.write(batch);
|
||||
batch.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[SimpleAuth] Error saving player data! " + e.getMessage());
|
||||
}
|
||||
|
||||
// Closing DB connection
|
||||
db.close();
|
||||
}
|
||||
|
||||
|
@ -131,6 +161,7 @@ public class SimpleAuth implements DedicatedServerModInitializer {
|
|||
// Marking player as not authenticated, (re)setting login tries to zero
|
||||
String uuid = convertUuid(player);
|
||||
SimpleAuth.deauthenticatedUsers.put(uuid, new PlayerCache(uuid, player));
|
||||
|
||||
// Teleporting player to spawn to hide its position
|
||||
if(config.main.spawnOnJoin)
|
||||
teleportPlayer(player, true);
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.samo_lego.simpleauth.commands;
|
|||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.command.arguments.BlockPosArgumentType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
@ -50,28 +51,23 @@ public class AuthCommand {
|
|||
)
|
||||
)
|
||||
.then(literal("setSpawn")
|
||||
.then(argument("here", word())
|
||||
.executes( ctx -> setSpawn(
|
||||
.executes( ctx -> setSpawn(
|
||||
ctx.getSource(),
|
||||
Objects.requireNonNull(ctx.getSource().getEntity()).dimension.getRawId(),
|
||||
ctx.getSource().getEntity().getX(),
|
||||
ctx.getSource().getEntity().getY(),
|
||||
ctx.getSource().getEntity().getZ()
|
||||
))
|
||||
.then(argument("dimension id", integer())
|
||||
.then(argument("position", BlockPosArgumentType.blockPos())
|
||||
.executes(ctx -> setSpawn(
|
||||
ctx.getSource(),
|
||||
Objects.requireNonNull(ctx.getSource().getEntity()).dimension.getRawId(),
|
||||
ctx.getSource().getEntity().getX(),
|
||||
ctx.getSource().getEntity().getY(),
|
||||
ctx.getSource().getEntity().getZ()
|
||||
))
|
||||
)
|
||||
.then(argument("dimensionId", integer())
|
||||
.then(argument("x", integer())
|
||||
.then(argument("y", integer())
|
||||
.then(argument("z", integer())
|
||||
.executes( ctx -> setSpawn(
|
||||
ctx.getSource(),
|
||||
getInteger(ctx, "dimensionId"),
|
||||
getInteger(ctx, "x"),
|
||||
getInteger(ctx, "y"),
|
||||
getInteger(ctx, "z")
|
||||
))
|
||||
)
|
||||
)
|
||||
getInteger(ctx, "dimension id"),
|
||||
BlockPosArgumentType.getLoadedBlockPos(ctx, "position").getX(),
|
||||
// +1 to not spawn player in ground
|
||||
BlockPosArgumentType.getLoadedBlockPos(ctx, "position").getY() + 1,
|
||||
BlockPosArgumentType.getLoadedBlockPos(ctx, "position").getZ()
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -75,22 +75,29 @@ public class AuthEventHandler {
|
|||
// Player joining the server
|
||||
public static void onPlayerJoin(ServerPlayerEntity player) {
|
||||
// If player is fake auth is not needed
|
||||
if(isPlayerFake(player))
|
||||
if (isPlayerFake(player))
|
||||
return;
|
||||
// Checking if session is still valid
|
||||
String uuid = convertUuid(player);
|
||||
PlayerCache playerCache = deauthenticatedUsers.getOrDefault(uuid, null);
|
||||
|
||||
if (
|
||||
playerCache != null &&
|
||||
playerCache.wasAuthenticated &&
|
||||
playerCache.validUntil >= System.currentTimeMillis() &&
|
||||
playerCache.lastIp.equals(player.getIp())
|
||||
) {
|
||||
deauthenticatedUsers.remove(uuid); // Makes player authenticated
|
||||
return;
|
||||
if (playerCache != null) {
|
||||
if (
|
||||
playerCache.wasAuthenticated &&
|
||||
playerCache.validUntil >= System.currentTimeMillis() &&
|
||||
playerCache.lastIp.equals(player.getIp())
|
||||
) {
|
||||
deauthenticatedUsers.remove(uuid); // Makes player authenticated
|
||||
return;
|
||||
}
|
||||
// Invalidating session
|
||||
playerCache.wasAuthenticated = false;
|
||||
}
|
||||
deauthenticatePlayer(player);
|
||||
else
|
||||
deauthenticatePlayer(player);
|
||||
|
||||
if(config.main.spawnOnJoin)
|
||||
teleportPlayer(player, true);
|
||||
|
||||
// Tries to rescue player from nether portal
|
||||
if(config.main.tryPortalRescue && player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL)) {
|
||||
|
@ -174,6 +181,7 @@ public class AuthEventHandler {
|
|||
PlayerCache playerCache = deauthenticatedUsers.get(convertUuid(player));
|
||||
if(playerCache == null)
|
||||
return;
|
||||
|
||||
playerCache.wasAuthenticated = true;
|
||||
// Setting the session expire time
|
||||
playerCache.validUntil = System.currentTimeMillis() + config.main.sessionTimeoutTime * 1000;
|
||||
|
|
|
@ -6,13 +6,10 @@ import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
|
|||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.samo_lego.simpleauth.event.entity.player.ChatCallback;
|
||||
import org.samo_lego.simpleauth.event.entity.player.PlayerMoveCallback;
|
||||
import org.samo_lego.simpleauth.event.item.TakeItemCallback;
|
||||
import org.samo_lego.simpleauth.storage.PlayerCache;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
@ -21,9 +18,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS;
|
||||
import static org.samo_lego.simpleauth.SimpleAuth.config;
|
||||
import static org.samo_lego.simpleauth.SimpleAuth.deauthenticatedUsers;
|
||||
import static org.samo_lego.simpleauth.utils.UuidConverter.convertUuid;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public abstract class MixinServerPlayNetworkHandler {
|
||||
|
@ -86,48 +80,4 @@ public abstract class MixinServerPlayNetworkHandler {
|
|||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method="disconnect(Lnet/minecraft/text/Text;)V",
|
||||
at = @At(value = "HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
// If player is disconnected because of sth (e.g. wrong password)
|
||||
// its position is set back to previous (e.g. not spawn)
|
||||
private void disconnect(Text reason, CallbackInfo ci) {
|
||||
if(config.main.spawnOnJoin) {
|
||||
PlayerCache cache = deauthenticatedUsers.get(convertUuid(player));
|
||||
// Puts player to last cached position
|
||||
this.player.teleport(
|
||||
this.server.getWorld(DimensionType.byRawId(cache.lastDimId)),
|
||||
cache.lastX,
|
||||
cache.lastY,
|
||||
cache.lastZ,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method="onDisconnected(Lnet/minecraft/text/Text;)V",
|
||||
at = @At(value = "HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
// If player is disconnected because of sth (e.g. wrong password)
|
||||
// its position is set back to previous (e.g. not spawn)
|
||||
private void onDisconnected(Text reason, CallbackInfo ci) {
|
||||
if(config.main.spawnOnJoin) {
|
||||
PlayerCache cache = deauthenticatedUsers.get(convertUuid(player));
|
||||
// Puts player to last cached position
|
||||
this.player.teleport(
|
||||
this.server.getWorld(DimensionType.byRawId(cache.lastDimId)),
|
||||
cache.lastX,
|
||||
cache.lastY,
|
||||
cache.lastZ,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class AuthConfig {
|
|||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
};
|
||||
}
|
||||
}
|
||||
public static class LangConfig {
|
||||
public String enterPassword = "§6You need to enter your password!";
|
||||
|
@ -91,7 +91,7 @@ public class AuthConfig {
|
|||
public String minPasswordChars = "§6Password needs to be at least %d characters long!";
|
||||
public String disallowedUsername = "§6Invalid username characters! Allowed character regex: %s";
|
||||
public String playerAlreadyOnline = "§cPlayer %s is already online!";
|
||||
public String worldSpawnSet = "";
|
||||
public String worldSpawnSet = "§aSpawn for logging in was set successfully.";
|
||||
}
|
||||
public static class ExperimentalConfig {
|
||||
// Prevents player being kicked because another player with the same name has joined the server
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.samo_lego.simpleauth.storage;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import static org.samo_lego.simpleauth.SimpleAuth.config;
|
||||
|
@ -20,12 +22,13 @@ public class PlayerCache {
|
|||
public double lastY;
|
||||
public double lastZ;
|
||||
|
||||
private static final JsonParser parser = new JsonParser();
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
|
||||
public PlayerCache(String uuid, ServerPlayerEntity player) {
|
||||
if(db.isClosed())
|
||||
return;
|
||||
|
||||
if(player != null) {
|
||||
this.lastIp = player.getIp();
|
||||
|
||||
|
@ -45,18 +48,47 @@ public class PlayerCache {
|
|||
this.lastZ = config.worldSpawn.z;
|
||||
}
|
||||
|
||||
this.wasAuthenticated = false;
|
||||
this.loginTries = 0;
|
||||
|
||||
|
||||
if(db.isUserRegistered(uuid)) {
|
||||
this.isRegistered = true;
|
||||
JsonObject json = parser.parse(db.getData(uuid)).getAsJsonObject();
|
||||
String data = db.getData(uuid);
|
||||
|
||||
// Getting (hashed) password
|
||||
JsonObject json = gson.fromJson(data, JsonObject.class);
|
||||
this.password = json.get("password").getAsString();
|
||||
|
||||
// If coordinates are same as the one from world spawn
|
||||
// we should check the DB for saved coords
|
||||
if(config.main.spawnOnJoin) {
|
||||
try {
|
||||
JsonElement lastLoc = json.get("lastLocation");
|
||||
if (
|
||||
lastLoc != null &&
|
||||
this.lastDimId == config.worldSpawn.dimensionId &&
|
||||
this.lastX == config.worldSpawn.x &&
|
||||
this.lastY == config.worldSpawn.y &&
|
||||
this.lastZ == config.worldSpawn.z
|
||||
) {
|
||||
// Getting DB coords
|
||||
JsonObject lastLocation = gson.fromJson(lastLoc.getAsString(), JsonObject.class);
|
||||
this.lastDimId = lastLocation.get("dimId").getAsInt();
|
||||
this.lastX = lastLocation.get("x").getAsDouble();
|
||||
this.lastY = lastLocation.get("y").getAsDouble();
|
||||
this.lastZ = lastLocation.get("z").getAsDouble();
|
||||
|
||||
// Removing location data from DB
|
||||
json.remove("lastLocation");
|
||||
db.updateUserData(uuid, json.toString());
|
||||
}
|
||||
} catch (JsonSyntaxException ignored) {
|
||||
// Player didn't have any coords in db to tp to
|
||||
}
|
||||
}
|
||||
this.isRegistered = true;
|
||||
}
|
||||
else {
|
||||
this.isRegistered = false;
|
||||
this.password = "";
|
||||
}
|
||||
this.wasAuthenticated = false;
|
||||
this.loginTries = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
|||
|
||||
public class SimpleAuthDatabase {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private DB levelDBStore;
|
||||
public DB levelDBStore;
|
||||
|
||||
// Connects to the DB
|
||||
public void openConnection() {
|
||||
|
@ -81,7 +81,7 @@ public class SimpleAuthDatabase {
|
|||
// Updates the password of the user
|
||||
public void updateUserData(String uuid, String data) {
|
||||
try {
|
||||
levelDBStore.put(bytes("UUID:" + uuid),bytes("data:" + data));
|
||||
levelDBStore.put(bytes("UUID:" + uuid), bytes("data:" + data));
|
||||
} catch (Error e) {
|
||||
LOGGER.error("[SimpleAuth] " + e.getMessage());
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class SimpleAuthDatabase {
|
|||
// Gets the hashed password from DB
|
||||
public String getData(String uuid){
|
||||
try {
|
||||
if(this.isUserRegistered(uuid)) // Gets password from db and removes "password:" prefix from it
|
||||
if(this.isUserRegistered(uuid)) // Gets password from db and removes "data:" prefix from it
|
||||
return new String(levelDBStore.get(bytes("UUID:" + uuid))).substring(5);
|
||||
} catch (Error e) {
|
||||
LOGGER.error("[SimpleAuth] Error getting password: " + e.getMessage());
|
||||
|
|
Loading…
Reference in New Issue