Merge branch 'master' into latest-snapshot
This commit is contained in:
commit
196eac3052
|
@ -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
|
||||||
|
|
17
build.gradle
17
build.gradle
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -2,42 +2,29 @@ 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
|
// Hashed password from DB
|
||||||
else {
|
else {
|
||||||
JsonObject json = parser.parse(SimpleAuth.DB.getData(uuid)).getAsJsonObject();
|
JsonObject json = parser.parse(SimpleAuth.DB.getData(uuid)).getAsJsonObject();
|
||||||
|
@ -46,24 +33,24 @@ public class AuthHelper {
|
||||||
|
|
||||||
if(hashed.equals(""))
|
if(hashed.equals(""))
|
||||||
return -1; // User is not yet registered
|
return -1; // User is not yet registered
|
||||||
|
|
||||||
// Verify password
|
// Verify password
|
||||||
return argon2.verify(hashed, pass) ? 1 : 0;
|
return verifyPassword(pass, hashed) ? 1 : 0;
|
||||||
} catch (Error e) {
|
|
||||||
logError("Argon2 error: " + e);
|
|
||||||
return 0;
|
|
||||||
} finally {
|
|
||||||
// Wipe confidential data
|
|
||||||
argon2.wipeArray(pass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String hashPassword(char[] pass) {
|
||||||
|
if(config.experimental.useBCryptLibrary)
|
||||||
|
return HasherBCrypt.hash(pass);
|
||||||
|
else
|
||||||
|
return HasherArgon2.hash(pass);
|
||||||
}
|
}
|
||||||
// Hashing the password with the Argon2 power
|
|
||||||
public static String hashPass(char[] pass) {
|
|
||||||
try {
|
private static boolean verifyPassword(char[] pass, String hashed) {
|
||||||
return argon2.hash(10, 65536, 1, pass);
|
if(config.experimental.useBCryptLibrary)
|
||||||
} catch (Error e) {
|
return HasherBCrypt.verify(pass, hashed);
|
||||||
logError(e.getMessage());
|
else
|
||||||
}
|
return HasherArgon2.verify(pass, hashed);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue