Merge branch 'master' into latest-snapshot

This commit is contained in:
samo_lego 2020-08-05 10:21:13 +02:00
commit f550ca1632
9 changed files with 126 additions and 34 deletions

View File

@ -1,5 +1,5 @@
plugins { plugins {
id 'fabric-loom' version '0.4.29' id 'fabric-loom' version '0.4-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
} }

View File

@ -10,7 +10,7 @@ loader_version=0.9.0+build.204
fabric_version=0.16.1+build.387-1.16 fabric_version=0.16.1+build.387-1.16
# Mod Properties # Mod Properties
mod_version = 1.5.0 mod_version = 1.5.1
maven_group = org.samo_lego maven_group = org.samo_lego
archives_base_name = simpleauth archives_base_name = simpleauth

View File

@ -56,7 +56,13 @@ public class SimpleAuth implements DedicatedServerModInitializer {
// It stores some data as well, e.g. login tries and user password // It stores some data as well, e.g. login tries and user password
public static HashMap<String, PlayerCache> deauthenticatedUsers = new HashMap<>(); public static HashMap<String, PlayerCache> deauthenticatedUsers = new HashMap<>();
// Boolean for easier checking if player is authenticated /**
* Checks whether player is authenticated
* Fake players always count as authenticated
*
* @param player player that needs to be checked
* @return false if player is de-authenticated, otherwise false
*/
public static boolean isAuthenticated(ServerPlayerEntity player) { public static boolean isAuthenticated(ServerPlayerEntity player) {
String uuid = convertUuid(player); String uuid = convertUuid(player);
return !deauthenticatedUsers.containsKey(uuid) || deauthenticatedUsers.get(uuid).wasAuthenticated; return !deauthenticatedUsers.containsKey(uuid) || deauthenticatedUsers.get(uuid).wasAuthenticated;
@ -152,7 +158,13 @@ public class SimpleAuth implements DedicatedServerModInitializer {
DB.close(); DB.close();
} }
// Getting not authenticated text /**
* Gets the text which tells the player
* to login or register, depending on account status
*
* @param player player who will get the message
* @return LiteralText with appropriate string (login or register)
*/
public static LiteralText notAuthenticated(PlayerEntity player) { public static LiteralText notAuthenticated(PlayerEntity player) {
final PlayerCache cache = deauthenticatedUsers.get(convertUuid(player)); final PlayerCache cache = deauthenticatedUsers.get(convertUuid(player));
if(SimpleAuth.config.main.enableGlobalPassword || cache.isRegistered) if(SimpleAuth.config.main.enableGlobalPassword || cache.isRegistered)
@ -164,7 +176,12 @@ public class SimpleAuth implements DedicatedServerModInitializer {
); );
} }
// Authenticates player and sends the message /**
* Authenticates player and sends the success message
*
* @param player player that needs to be authenticated
* @param msg message to be send to the player
*/
public static void authenticatePlayer(ServerPlayerEntity player, Text msg) { public static void authenticatePlayer(ServerPlayerEntity player, Text msg) {
PlayerCache playerCache = deauthenticatedUsers.get(convertUuid(player)); PlayerCache playerCache = deauthenticatedUsers.get(convertUuid(player));
// Teleporting player back // Teleporting player back
@ -198,7 +215,11 @@ public class SimpleAuth implements DedicatedServerModInitializer {
player.sendMessage(msg, false); player.sendMessage(msg, false);
} }
// De-authenticates player /**
* De-authenticates the player
*
* @param player player that needs to be de-authenticated
*/
public static void deauthenticatePlayer(ServerPlayerEntity player) { public static void deauthenticatePlayer(ServerPlayerEntity player) {
if(DB.isClosed()) if(DB.isClosed())
return; return;
@ -230,13 +251,24 @@ public class SimpleAuth implements DedicatedServerModInitializer {
}, SimpleAuth.config.main.delay * 1000); }, SimpleAuth.config.main.delay * 1000);
} }
// Checking is player is a fake (carpetmod) player /**
* Checks whether player is a fake player (from CarpetMod)
*
* @param player player that needs to be checked
* @return true if player is fake, otherwise false
*/
public static boolean isPlayerFake(PlayerEntity player) { public static boolean isPlayerFake(PlayerEntity player) {
// We ask CarpetHelper class since it has the imports needed // We ask CarpetHelper class since it has the imports needed
return FabricLoader.getInstance().isModLoaded("carpet") && isPlayerCarpetFake(player); return FabricLoader.getInstance().isModLoaded("carpet") && isPlayerCarpetFake(player);
} }
// Teleports player to spawn or last location when authenticating /**
* Teleports player to spawn or last location that is recorded
* Last location means the location before de-authentication
*
* @param player player that needs to be teleported
* @param toSpawn whether to teleport player to spawn (provided in config) or last recorded position
*/
public static void teleportPlayer(ServerPlayerEntity player, boolean toSpawn) { public static void teleportPlayer(ServerPlayerEntity player, boolean toSpawn) {
MinecraftServer server = player.getServer(); MinecraftServer server = player.getServer();
if(server == null || config.worldSpawn.dimension == null) if(server == null || config.worldSpawn.dimension == null)

View File

@ -114,7 +114,6 @@ public class AuthEventHandler {
// Teleporting player to the middle of the block // Teleporting player to the middle of the block
player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5);
playerCache.wasInPortal = true;
} }
} }
@ -154,7 +153,17 @@ public class AuthEventHandler {
// Player movement // Player movement
public static ActionResult onPlayerMove(PlayerEntity player) { public static ActionResult onPlayerMove(PlayerEntity player) {
if(!isAuthenticated((ServerPlayerEntity) player) && !config.experimental.allowMovement) { // Player will fall if enabled (prevent fly kick)
boolean auth = isAuthenticated((ServerPlayerEntity) player);
if(!auth && config.main.allowFalling && !player.isOnGround() && !player.isInsideWaterOrBubbleColumn()) {
if(player.isInvulnerable())
player.setInvulnerable(false);
return ActionResult.PASS;
}
// Otherwise movement should be disabled
else if(!auth && !config.experimental.allowMovement) {
if(!player.isInvulnerable())
player.setInvulnerable(true);
return ActionResult.FAIL; return ActionResult.FAIL;
} }
return ActionResult.PASS; return ActionResult.PASS;

View File

@ -53,8 +53,13 @@ public class AuthConfig {
// Visit https://github.com/samolego/SimpleAuth/wiki/Sessions for more info // Visit https://github.com/samolego/SimpleAuth/wiki/Sessions for more info
public int sessionTimeoutTime = 60; public int sessionTimeoutTime = 60;
// Should deauthenticated players fall if the login mid-air?
public boolean allowFalling = false;
// Whether to tp player to spawn when joining (to hide coordinates) // Whether to tp player to spawn when joining (to hide coordinates)
public boolean spawnOnJoin = false; public boolean spawnOnJoin = false;
// Data for spawn (where deauthenticated players are teleported)
public static class WorldSpawn { public static class WorldSpawn {
public String dimension; public String dimension;
public double x; public double x;

View File

@ -1,32 +1,42 @@
package org.samo_lego.simpleauth.storage; package org.samo_lego.simpleauth.storage;
import com.google.gson.*; import com.google.gson.*;
import net.minecraft.block.Blocks;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import static org.samo_lego.simpleauth.SimpleAuth.DB; import static org.samo_lego.simpleauth.SimpleAuth.DB;
import static org.samo_lego.simpleauth.SimpleAuth.config; import static org.samo_lego.simpleauth.SimpleAuth.config;
/**
* Class used for storing the deauthenticated player's cache
*/
public class PlayerCache { public class PlayerCache {
// Whether player is registered
public boolean isRegistered; public boolean isRegistered;
// If player from another location (different IP) joins, session is invalidated using this boolean // If player from another location (different IP) joins, session is invalidated using this boolean
public boolean wasAuthenticated; public boolean wasAuthenticated;
// Hashed password of player
public String password; public String password;
// How many times player has tried to login
public int loginTries; public int loginTries;
// Last IP of player, used for sessions
public String lastIp; public String lastIp;
// Time until session is valid
public long validUntil; public long validUntil;
public int lastAir = 300; // Player stats before de-authenticating
public int lastAir;
public boolean wasOnFire; public boolean wasOnFire;
public boolean wasInPortal;
// Last recorded position before de-authenticating
public String lastDim; public String lastDim;
public double lastX; public double lastX;
public double lastY; public double lastY;
public double lastZ; public double lastZ;
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
public boolean wasInPortal;
public PlayerCache(String uuid, ServerPlayerEntity player) { public PlayerCache(String uuid, ServerPlayerEntity player) {
if(DB.isClosed()) if(DB.isClosed())
@ -40,12 +50,15 @@ public class PlayerCache {
// Setting position cache // Setting position cache
this.lastDim = String.valueOf(player.getEntityWorld().getRegistryKey().getValue()); this.lastDim = String.valueOf(player.getEntityWorld().getRegistryKey().getValue());
this.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL);
this.lastX = player.getX(); this.lastX = player.getX();
this.lastY = player.getY(); this.lastY = player.getY();
this.lastZ = player.getZ(); this.lastZ = player.getZ();
} }
else { else {
this.wasOnFire = false; this.wasOnFire = false;
this.wasInPortal = false;
this.lastAir = 300;
} }
if(DB.isUserRegistered(uuid)) { if(DB.isUserRegistered(uuid)) {
@ -96,6 +109,5 @@ public class PlayerCache {
} }
this.wasAuthenticated = false; this.wasAuthenticated = false;
this.loginTries = 0; this.loginTries = 0;
this.wasInPortal = false;
} }
} }

View File

@ -12,12 +12,17 @@ public class AuthHelper {
// Json parser // Json parser
private static final JsonParser parser = new JsonParser(); private static final JsonParser parser = new JsonParser();
// Returns 1 if password is correct, 0 if not /**
// and -1 if user is not registered yet * Checks password of user
public static int checkPass(String uuid, char[] pass) { *
* @param uuid uuid of player, stored in database
* @param password password that needs to be checked
* @return 1 for pass, 0 if password is false, -1 if user is not yet registered
*/
public static int checkPass(String uuid, char[] password) {
if(config.main.enableGlobalPassword) { if(config.main.enableGlobalPassword) {
// We have global password enabled // We have global password enabled
return verifyPassword(pass, config.main.globalPassword) ? 1 : 0; return verifyPassword(password, config.main.globalPassword) ? 1 : 0;
} }
else { else {
String hashed; String hashed;
@ -35,18 +40,23 @@ public class AuthHelper {
return -1; // User is not yet registered return -1; // User is not yet registered
// Verify password // Verify password
return verifyPassword(pass, hashed) ? 1 : 0; return verifyPassword(password, hashed) ? 1 : 0;
} }
} }
public static String hashPassword(char[] pass) { /**
* Hashes password with algorithm, depending on config
*
* @param password character array of password string
* @return hashed password as string
*/
public static String hashPassword(char[] password) {
if(config.experimental.useBCryptLibrary) if(config.experimental.useBCryptLibrary)
return HasherBCrypt.hash(pass); return HasherBCrypt.hash(password);
else else
return HasherArgon2.hash(pass); return HasherArgon2.hash(password);
} }
private static boolean verifyPassword(char[] pass, String hashed) { private static boolean verifyPassword(char[] pass, String hashed) {
if(config.experimental.useBCryptLibrary) if(config.experimental.useBCryptLibrary)
return HasherBCrypt.verify(pass, hashed); return HasherBCrypt.verify(pass, hashed);

View File

@ -10,23 +10,35 @@ public class HasherArgon2 {
// Creating the instance // Creating the instance
private static final Argon2 HASHER = Argon2Factory.create(); private static final Argon2 HASHER = Argon2Factory.create();
public static boolean verify(char[] pass, String hashed) { /**
* Verifies password
*
* @param password character array of password string
* @param hashed hashed password
* @return true if password was correct
*/
public static boolean verify(char[] password, String hashed) {
try { try {
return HASHER.verify(hashed, pass); return HASHER.verify(hashed, password);
} }
catch (Error e) { catch (Error e) {
logError("Argon2 password verification error: " + e); logError("Argon2 password verification error: " + e);
return false; return false;
} finally { } finally {
// Wipe confidential data // Wipe confidential data
HASHER.wipeArray(pass); HASHER.wipeArray(password);
} }
} }
// Hashing the password with the Argon2 power /**
public static String hash(char[] pass) { * Hashes the password
*
* @param password character array of password string that needs to be hashed
* @return string
*/
public static String hash(char[] password) {
try { try {
return HASHER.hash(10, 65536, 1, pass); return HASHER.hash(10, 65536, 1, password);
} catch (Error e) { } catch (Error e) {
logError("Argon2 password hashing error: " + e); logError("Argon2 password hashing error: " + e);
} }

View File

@ -6,9 +6,16 @@ import static org.samo_lego.simpleauth.utils.SimpleLogger.logError;
public class HasherBCrypt { public class HasherBCrypt {
public static boolean verify(char[] pass, String hashed) { /**
* Verifies password
*
* @param password character array of password string
* @param hashed hashed password
* @return true if password was correct
*/
public static boolean verify(char[] password, String hashed) {
try { try {
return BCrypt.verifyer().verify(pass, hashed).verified; return BCrypt.verifyer().verify(password, hashed).verified;
} }
catch (Error e) { catch (Error e) {
logError("BCrypt password verification error: " + e); logError("BCrypt password verification error: " + e);
@ -16,10 +23,15 @@ public class HasherBCrypt {
} }
} }
// Hashing the password with the Argon2 power /**
public static String hash(char[] pass) { * Hashes the password
*
* @param password character array of password string that needs to be hashed
* @return string
*/
public static String hash(char[] password) {
try { try {
return BCrypt.withDefaults().hashToString(12, pass); return BCrypt.withDefaults().hashToString(12, password);
} catch (Error e) { } catch (Error e) {
logError("BCrypt password hashing error: " + e); logError("BCrypt password hashing error: " + e);
} }