Merge branch 'master' into latest-snapshot

This commit is contained in:
samo_lego 2020-07-29 15:16:05 +02:00
commit 196eac3052
12 changed files with 138 additions and 66 deletions

View File

@ -6,11 +6,13 @@
[![Closed Issues](https://img.shields.io/github/issues-closed/samolego/simpleauth.svg)](https://github.com/samolego/SimpleAuth/issues?q=is%3Aissue+is%3Aclosed) [![Closed Issues](https://img.shields.io/github/issues-closed/samolego/simpleauth.svg)](https://github.com/samolego/SimpleAuth/issues?q=is%3Aissue+is%3Aclosed)
[![Curseforge downloads](http://cf.way2muchnoise.eu/full_simpleauth_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/simpleauth) [![Curseforge downloads](http://cf.way2muchnoise.eu/full_simpleauth_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/simpleauth)
Requires Fabric API. [<img src="https://i.imgur.com/Ol1Tcf8.png" alt="Requires Fabric API." width="200px" href="https://www.curseforge.com/minecraft/mc-mods/fabric-api">](https://www.curseforge.com/minecraft/mc-mods/fabric-api)
## License ## License
Libraries that the project is using: Libraries that the project is using:
- `Argon2 (LGPLv3)` https://github.com/phxql/argon2-jvm - `Argon2 (LGPLv3)` https://github.com/phxql/argon2-jvm
- `BCrypt (Apache 2)` https://github.com/patrickfav/bcrypt
- `Bytes (Apache 2)` https://github.com/patrickfav/bytes-java
- `leveldb (BSD-3-Clause)` https://github.com/google/leveldb - `leveldb (BSD-3-Clause)` https://github.com/google/leveldb
- `JNA (Apache 2 || LGPLv3)` https://github.com/java-native-access/jna - `JNA (Apache 2 || LGPLv3)` https://github.com/java-native-access/jna
@ -51,7 +53,7 @@ And this to your `gradle.properties`
```properties ```properties
# By tag (version) # By tag (version)
# SimpleAuth version (this might not be the latest version) # SimpleAuth version (this might not be the latest version)
simpleauth_version = 1.4.6 simpleauth_version = 1.4.8
# Or this (by branch) # Or this (by branch)
# SimpleAuth branches # SimpleAuth branches

View File

@ -32,11 +32,20 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// Argon2 library for password hashing
implementation 'de.mkammerer:argon2-jvm:2.6'
include 'de.mkammerer:argon2-jvm:2.6'
// leveldb // Password hashing
// Argon2
implementation "de.mkammerer:argon2-jvm:${argon2_version}"
include "de.mkammerer:argon2-jvm:${argon2_version}"
// BCrypt
implementation "at.favre.lib:bcrypt:${bcrypt_version}"
implementation "at.favre.lib:bytes:${bytes_version}"
include "at.favre.lib:bcrypt:${bcrypt_version}"
include "at.favre.lib:bytes:${bytes_version}"
// Storage
// leveldb database
implementation group: 'org.iq80.leveldb', name: 'leveldb', version: '0.12' implementation group: 'org.iq80.leveldb', name: 'leveldb', version: '0.12'
implementation group: 'org.iq80.leveldb', name: 'leveldb-api', version: '0.12' implementation group: 'org.iq80.leveldb', name: 'leveldb-api', version: '0.12'
include group: 'org.iq80.leveldb', name: 'leveldb', version: '0.12' include group: 'org.iq80.leveldb', name: 'leveldb', version: '0.12'

View File

@ -10,10 +10,15 @@ loader_version=0.9.0+build.204
fabric_version=0.16.0+build.386-1.16 fabric_version=0.16.0+build.386-1.16
# Mod Properties # Mod Properties
mod_version = 1.4.8 mod_version = 1.5.0
maven_group = org.samo_lego maven_group = org.samo_lego
archives_base_name = simpleauth archives_base_name = simpleauth
# Carpet for debugging # Carpet for debugging
carpet_core_version = 1.4.0+v200623 carpet_core_version = 1.4.0+v200623
carpet_branch = 1.16 carpet_branch = 1.16
# Hashing
argon2_version = 2.7
bcrypt_version = 0.9.0
bytes_version = 1.3.0

View File

@ -120,7 +120,7 @@ public class AccountCommand {
} }
// JSON object holding password (may hold some other info in the future) // JSON object holding password (may hold some other info in the future)
JsonObject playerdata = new JsonObject(); JsonObject playerdata = new JsonObject();
String hash = AuthHelper.hashPass(newPass.toCharArray()); String hash = AuthHelper.hashPassword(newPass.toCharArray());
playerdata.addProperty("password", hash); playerdata.addProperty("password", hash);
SimpleAuth.DB.updateUserData(convertUuid(player), playerdata.toString()); SimpleAuth.DB.updateUserData(convertUuid(player), playerdata.toString());

View File

@ -114,7 +114,7 @@ public class AuthCommand {
// Different thread to avoid lag spikes // Different thread to avoid lag spikes
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
// Writing the global pass to config // Writing the global pass to config
config.main.globalPassword = AuthHelper.hashPass(pass.toCharArray()); config.main.globalPassword = AuthHelper.hashPassword(pass.toCharArray());
config.main.enableGlobalPassword = true; config.main.enableGlobalPassword = true;
config.save(new File("./mods/SimpleAuth/config.json")); config.save(new File("./mods/SimpleAuth/config.json"));
}); });
@ -133,6 +133,7 @@ public class AuthCommand {
config.worldSpawn.x = x; config.worldSpawn.x = x;
config.worldSpawn.y = y; config.worldSpawn.y = y;
config.worldSpawn.z = z; config.worldSpawn.z = z;
config.main.spawnOnJoin = true;
config.save(new File("./mods/SimpleAuth/config.json")); config.save(new File("./mods/SimpleAuth/config.json"));
// Getting sender // Getting sender
@ -167,7 +168,7 @@ public class AuthCommand {
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
// JSON object holding password (may hold some other info in the future) // JSON object holding password (may hold some other info in the future)
JsonObject playerdata = new JsonObject(); JsonObject playerdata = new JsonObject();
String hash = AuthHelper.hashPass(password.toCharArray()); String hash = AuthHelper.hashPassword(password.toCharArray());
playerdata.addProperty("password", hash); playerdata.addProperty("password", hash);
if (DB.registerUser(uuid, playerdata.toString())) { if (DB.registerUser(uuid, playerdata.toString())) {
@ -188,7 +189,7 @@ public class AuthCommand {
THREADPOOL.submit(() -> { THREADPOOL.submit(() -> {
// JSON object holding password (may hold some other info in the future) // JSON object holding password (may hold some other info in the future)
JsonObject playerdata = new JsonObject(); JsonObject playerdata = new JsonObject();
String hash = AuthHelper.hashPass(password.toCharArray()); String hash = AuthHelper.hashPassword(password.toCharArray());
playerdata.addProperty("password", hash); playerdata.addProperty("password", hash);
DB.updateUserData(uuid, playerdata.toString()); DB.updateUserData(uuid, playerdata.toString());

View File

@ -63,7 +63,7 @@ public class RegisterCommand {
), false); ), false);
return; return;
} }
String hash = AuthHelper.hashPass(pass1.toCharArray()); String hash = AuthHelper.hashPassword(pass1.toCharArray());
// JSON object holding password (may hold some other info in the future) // JSON object holding password (may hold some other info in the future)
JsonObject playerdata = new JsonObject(); JsonObject playerdata = new JsonObject();
playerdata.addProperty("password", hash); playerdata.addProperty("password", hash);

View File

@ -12,7 +12,6 @@ import net.minecraft.text.LiteralText;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.samo_lego.simpleauth.SimpleAuth;
import org.samo_lego.simpleauth.mixin.BlockUpdateS2CPacketAccessor; import org.samo_lego.simpleauth.mixin.BlockUpdateS2CPacketAccessor;
import org.samo_lego.simpleauth.storage.PlayerCache; import org.samo_lego.simpleauth.storage.PlayerCache;
@ -81,8 +80,8 @@ public class AuthEventHandler {
return; return;
} }
// Ugly fix for #13 // Ugly fix for #13
player.setInvulnerable(SimpleAuth.config.experimental.playerInvulnerable); player.setInvulnerable(config.experimental.playerInvulnerable);
player.setInvisible(SimpleAuth.config.experimental.playerInvisible); player.setInvisible(config.experimental.playerInvisible);
// Invalidating session // Invalidating session
playerCache.wasAuthenticated = false; playerCache.wasAuthenticated = false;
@ -91,6 +90,7 @@ public class AuthEventHandler {
else { else {
deauthenticatePlayer(player); deauthenticatePlayer(player);
playerCache = deauthenticatedUsers.get(uuid); playerCache = deauthenticatedUsers.get(uuid);
playerCache.wasOnFire = false;
} }
if(config.main.spawnOnJoin) if(config.main.spawnOnJoin)

View File

@ -115,6 +115,8 @@ public class AuthConfig {
public boolean allowItemUse = false; public boolean allowItemUse = false;
// Allows attacking mobs // Allows attacking mobs
public boolean allowEntityPunch = false; public boolean allowEntityPunch = false;
// Whether to use BCrypt instead of Argon2 (GLIBC_2.25 error)
public boolean useBCryptLibrary = false;
} }
private static final Gson gson = new GsonBuilder() private static final Gson gson = new GsonBuilder()
.setPrettyPrinting() .setPrettyPrinting()

View File

@ -17,7 +17,7 @@ public class PlayerCache {
public long validUntil; public long validUntil;
public int lastAir = 300; public int lastAir = 300;
public boolean wasOnFire = false; public boolean wasOnFire;
public String lastDim; public String lastDim;
public double lastX; public double lastX;
@ -44,6 +44,9 @@ public class PlayerCache {
this.lastY = player.getY(); this.lastY = player.getY();
this.lastZ = player.getZ(); this.lastZ = player.getZ();
} }
else {
this.wasOnFire = false;
}
if(DB.isUserRegistered(uuid)) { if(DB.isUserRegistered(uuid)) {
String data = DB.getData(uuid); String data = DB.getData(uuid);
@ -73,10 +76,10 @@ public class PlayerCache {
if (lastLoc != null) { if (lastLoc != null) {
// Getting DB coords // Getting DB coords
JsonObject lastLocation = gson.fromJson(lastLoc.getAsString(), JsonObject.class); JsonObject lastLocation = gson.fromJson(lastLoc.getAsString(), JsonObject.class);
this.lastDim = lastLocation.get("dim").getAsString(); this.lastDim = lastLocation.get("dim").isJsonNull() ? config.worldSpawn.dimension : lastLocation.get("dim").getAsString();
this.lastX = lastLocation.get("x").getAsDouble(); this.lastX = lastLocation.get("x").isJsonNull() ? config.worldSpawn.x : lastLocation.get("x").getAsDouble();
this.lastY = lastLocation.get("y").getAsDouble(); this.lastY = lastLocation.get("y").isJsonNull() ? config.worldSpawn.y : lastLocation.get("y").getAsDouble();
this.lastZ = lastLocation.get("z").getAsDouble(); this.lastZ = lastLocation.get("z").isJsonNull() ? config.worldSpawn.z : lastLocation.get("z").getAsDouble();
// Removing location data from DB // Removing location data from DB
json.remove("lastLocation"); json.remove("lastLocation");

View File

@ -2,68 +2,55 @@ package org.samo_lego.simpleauth.utils;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import org.samo_lego.simpleauth.SimpleAuth; import org.samo_lego.simpleauth.SimpleAuth;
import org.samo_lego.simpleauth.utils.hashing.HasherArgon2;
import org.samo_lego.simpleauth.utils.hashing.HasherBCrypt;
import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; import static org.samo_lego.simpleauth.SimpleAuth.config;
public class AuthHelper { public class AuthHelper {
// Creating the instance
private static final Argon2 argon2 = Argon2Factory.create();
// 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 // Returns 1 if password is correct, 0 if not
// and -1 if user is not registered yet // and -1 if user is not registered yet
public static int checkPass(String uuid, char[] pass) { public static int checkPass(String uuid, char[] pass) {
if(SimpleAuth.config.main.enableGlobalPassword) { if(config.main.enableGlobalPassword) {
// We have global password enabled // We have global password enabled
try { return verifyPassword(pass, config.main.globalPassword) ? 1 : 0;
return argon2.verify(SimpleAuth.config.main.globalPassword, pass) ? 1 : 0;
}
catch (Error e) {
logError("Argon2 error: " + e);
return 0;
} finally {
// Wipe confidential data
argon2.wipeArray(pass);
}
} }
else { else {
try { String hashed;
String hashed; // Password from cache
// Password from cache if(SimpleAuth.deauthenticatedUsers.containsKey(uuid))
if(SimpleAuth.deauthenticatedUsers.containsKey(uuid)) hashed = SimpleAuth.deauthenticatedUsers.get(uuid).password;
hashed = SimpleAuth.deauthenticatedUsers.get(uuid).password;
// Hashed password from DB
else {
JsonObject json = parser.parse(SimpleAuth.DB.getData(uuid)).getAsJsonObject();
hashed = json.get("password").getAsString();
}
if(hashed.equals("")) // Hashed password from DB
return -1; // User is not yet registered else {
// Verify password JsonObject json = parser.parse(SimpleAuth.DB.getData(uuid)).getAsJsonObject();
return argon2.verify(hashed, pass) ? 1 : 0; hashed = json.get("password").getAsString();
} catch (Error e) {
logError("Argon2 error: " + e);
return 0;
} finally {
// Wipe confidential data
argon2.wipeArray(pass);
} }
if(hashed.equals(""))
return -1; // User is not yet registered
// Verify password
return verifyPassword(pass, hashed) ? 1 : 0;
} }
} }
// Hashing the password with the Argon2 power
public static String hashPass(char[] pass) { public static String hashPassword(char[] pass) {
try { if(config.experimental.useBCryptLibrary)
return argon2.hash(10, 65536, 1, pass); return HasherBCrypt.hash(pass);
} catch (Error e) { else
logError(e.getMessage()); return HasherArgon2.hash(pass);
} }
return null;
private static boolean verifyPassword(char[] pass, String hashed) {
if(config.experimental.useBCryptLibrary)
return HasherBCrypt.verify(pass, hashed);
else
return HasherArgon2.verify(pass, hashed);
} }
} }

View File

@ -0,0 +1,35 @@
package org.samo_lego.simpleauth.utils.hashing;
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import static org.samo_lego.simpleauth.utils.SimpleLogger.logError;
public class HasherArgon2 {
// Creating the instance
private static final Argon2 HASHER = Argon2Factory.create();
public static boolean verify(char[] pass, String hashed) {
try {
return HASHER.verify(hashed, pass);
}
catch (Error e) {
logError("Argon2 password verification error: " + e);
return false;
} finally {
// Wipe confidential data
HASHER.wipeArray(pass);
}
}
// Hashing the password with the Argon2 power
public static String hash(char[] pass) {
try {
return HASHER.hash(10, 65536, 1, pass);
} catch (Error e) {
logError("Argon2 password hashing error: " + e);
}
return null;
}
}

View File

@ -0,0 +1,28 @@
package org.samo_lego.simpleauth.utils.hashing;
import at.favre.lib.crypto.bcrypt.BCrypt;
import static org.samo_lego.simpleauth.utils.SimpleLogger.logError;
public class HasherBCrypt {
public static boolean verify(char[] pass, String hashed) {
try {
return BCrypt.verifyer().verify(pass, hashed).verified;
}
catch (Error e) {
logError("BCrypt password verification error: " + e);
return false;
}
}
// Hashing the password with the Argon2 power
public static String hash(char[] pass) {
try {
return BCrypt.withDefaults().hashToString(12, pass);
} catch (Error e) {
logError("BCrypt password hashing error: " + e);
}
return null;
}
}