Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Online authentication integration #15

Merged
merged 11 commits into from
Jul 11, 2021
49 changes: 45 additions & 4 deletions src/main/java/com/dqu/simplerauth/AuthMod.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
package com.dqu.simplerauth;

import com.dqu.simplerauth.commands.*;
import com.dqu.simplerauth.managers.ConfigManager;
import com.dqu.simplerauth.managers.DbManager;
import com.dqu.simplerauth.managers.LangManager;
import com.dqu.simplerauth.managers.PlayerManager;
import com.dqu.simplerauth.managers.*;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class AuthMod implements ModInitializer {
public static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = new Gson();
public static PlayerManager playerManager = new PlayerManager();

@Override
public void onInitialize() {
ConfigManager.loadConfig(); // Loads config file
DbManager.loadDatabase(); // Loads password database
CacheManager.loadCache(); // Loads cache
LangManager.loadTranslations("en"); // Loads translations
CommandRegistrationCallback.EVENT.register(((dispatcher, dedicated) -> {
LoginCommand.registerCommand(dispatcher);
RegisterCommand.registerCommand(dispatcher);
ChangePasswordCommand.registerCommand(dispatcher);
OnlineAuthCommand.registerCommand(dispatcher);
}));
}

public static boolean doesMinecraftAccountExist(String username) {
String content = "";
if (CacheManager.getMinecraftAccount(username) != null) {
return true;
}

try {
HttpsURLConnection connection = (HttpsURLConnection) new URL("https://api.mojang.com/users/profiles/minecraft/" + username).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);

int response = connection.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
InputStream stream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
StringBuilder stringBuilder = new StringBuilder();
String out;
while ((out = bufferedReader.readLine()) != null) {
stringBuilder.append(out);
}
content = stringBuilder.toString();
} else return false;
} catch (Exception e) {
AuthMod.LOGGER.error(e);
return false;
}

JsonObject jsonObject = GSON.fromJson(content, JsonObject.class);
CacheManager.addMinecraftAccount(username, jsonObject.get("id").getAsString());
return true;
}
}
132 changes: 132 additions & 0 deletions src/main/java/com/dqu/simplerauth/commands/OnlineAuthCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.dqu.simplerauth.commands;

import com.dqu.simplerauth.AuthMod;
import com.dqu.simplerauth.listeners.OnOnlineAuthChanged;
import com.dqu.simplerauth.managers.ConfigManager;
import com.dqu.simplerauth.managers.DbManager;
import com.dqu.simplerauth.managers.LangManager;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;

import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;

public class OnlineAuthCommand {
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(literal("onlineauth")
.executes(ctx -> {
ServerCommandSource source = ctx.getSource();
ServerPlayerEntity player = source.getPlayer();
executeEnable(player, source, null);
return 1;
})
.then(literal("enable")
.then(argument("password", StringArgumentType.word())
.executes(ctx -> {
String password = StringArgumentType.getString(ctx, "password");
ServerCommandSource source = ctx.getSource();
ServerPlayerEntity player = source.getPlayer();
executeEnable(player, source, password);
return 1;
})
)
)
.then(literal("disable")
.executes(ctx -> {
ServerCommandSource source = ctx.getSource();
ServerPlayerEntity player = source.getPlayer();
executeDisable(player, source, null);
return 1;
})
.then(argument("password", StringArgumentType.word())
.executes(ctx -> {
String password = StringArgumentType.getString(ctx, "password");
ServerCommandSource source = ctx.getSource();
ServerPlayerEntity player = source.getPlayer();
executeDisable(player, source, password);
return 1;
})
)
)
);
}

private static void executeEnable(ServerPlayerEntity player, ServerCommandSource source, @Nullable String password) {
String username = player.getEntityName();

if (checkFeatureDisabled(source)) {
return;
}

if (!DbManager.isPlayerRegistered(username)) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.notregistered"), false);
return;
} else if (DbManager.getUseOnlineAuth(username)) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.alreadyenabled"), false);
return;
} else if (!AuthMod.doesMinecraftAccountExist(username)) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.cannotenable"), false);
return;
}

if (password != null) {
if (DbManager.isPasswordCorrect(username, password)) {
DbManager.setUseOnlineAuth(username, true);
OnOnlineAuthChanged.onEnabled(player);
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.enabled"), false);
} else {
source.sendFeedback(LangManager.getLiteralText("command.general.notmatch"), false);
}
} else {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.warning"), false);
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.confirmenable"), false);
}
}

private static void executeDisable(ServerPlayerEntity player, ServerCommandSource source, @Nullable String password) {
String username = player.getEntityName();

if (checkFeatureDisabled(source)) {
return;
}

if (!DbManager.isPlayerRegistered(username)) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.notregistered"), false);
return;
} else if (!DbManager.getUseOnlineAuth(username)) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.alreadydisabled"), false);
return;
}

if (password != null) {
if (DbManager.isPasswordCorrect(username, password)) {
DbManager.setUseOnlineAuth(username, false);
OnOnlineAuthChanged.onDisabled(player);
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.disabled"), false);
} else {
source.sendFeedback(LangManager.getLiteralText("command.general.notmatch"), false);
}
} else {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.warning"), false);
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.confirmdisable"), false);
}
}

private static boolean checkFeatureDisabled(ServerCommandSource source) {
String authtype = ConfigManager.getAuthType();
boolean optionalOnlineAuth = ConfigManager.getBoolean("optional-online-auth");

if (authtype.equals("global")) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.globaltype"), false);
return true;
} else if (!optionalOnlineAuth) {
source.sendFeedback(LangManager.getLiteralText("command.onlineauth.featuredisabled"), false);
return true;
}

return false;
}
}
102 changes: 102 additions & 0 deletions src/main/java/com/dqu/simplerauth/listeners/OnOnlineAuthChanged.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.dqu.simplerauth.listeners;

import com.dqu.simplerauth.AuthMod;
import com.dqu.simplerauth.managers.CacheManager;
import com.google.gson.JsonObject;
import com.mojang.authlib.GameProfile;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.*;
import net.minecraft.server.network.ServerPlayerEntity;

import java.io.IOException;
import java.util.UUID;

public class OnOnlineAuthChanged {
public static void onEnabled(ServerPlayerEntity player) {
String username = player.getEntityName();
MinecraftServer server = player.getServer();
if (server == null) return; // Shouldn't happen
PlayerManager playerManager = server.getPlayerManager();

// Update uuids
JsonObject cachedAccount = CacheManager.getMinecraftAccount(username);
if (cachedAccount == null) {
return; // Shouldn't happen
}

String onlineUuid = cachedAccount.get("online-uuid").getAsString();
// UUID.fromString doesn't work on a uuid without dashes, we need to add them back before creating the UUID
onlineUuid = onlineUuid.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");

GameProfile onlineProfile = new GameProfile(UUID.fromString(onlineUuid), username);
GameProfile offlineProfile = player.getGameProfile(); // The player is offline when this is executed

// Update ops uuid
OperatorList ops = playerManager.getOpList();
OperatorEntry opEntry = ops.get(offlineProfile);
if (opEntry != null) {
ops.remove(offlineProfile);
ops.add(new OperatorEntry(onlineProfile, opEntry.getPermissionLevel(), opEntry.canBypassPlayerLimit()));
try {
ops.save();
} catch (IOException e) {
AuthMod.LOGGER.error("Failed to save updated operator list for username '{}', who enabled online authentication", username, e);
}
}

if (playerManager.isWhitelistEnabled()) {
// Update whitelist uuid
Whitelist whitelist = playerManager.getWhitelist();

if (whitelist.isAllowed(offlineProfile)) {
whitelist.remove(offlineProfile);
whitelist.add(new WhitelistEntry(onlineProfile));
try {
whitelist.save();
} catch (IOException e) {
AuthMod.LOGGER.error("Failed to save updated whitelist for username '{}', who enabled online authentication", username, e);
}
}
}
}

public static void onDisabled(ServerPlayerEntity player) {
String username = player.getEntityName();
MinecraftServer server = player.getServer();
if (server == null) return; // Shouldn't happen
PlayerManager playerManager = server.getPlayerManager();

// Update uuids
UUID offlineUuid = PlayerEntity.getOfflinePlayerUuid(username);
GameProfile offlineProfile = new GameProfile(offlineUuid, username);
GameProfile onlineProfile = player.getGameProfile(); // The player is online when this is executed

// Update ops uuid
OperatorList ops = playerManager.getOpList();
OperatorEntry opEntry = ops.get(onlineProfile);
if (opEntry != null) {
ops.remove(onlineProfile);
ops.add(new OperatorEntry(offlineProfile, opEntry.getPermissionLevel(), opEntry.canBypassPlayerLimit()));
try {
ops.save();
} catch (IOException e) {
AuthMod.LOGGER.error("Failed to save updated operator list for username '{}', who disabled online authentication", username, e);
}
}

if (playerManager.isWhitelistEnabled()) {
// Update whitelist uuid
Whitelist whitelist = playerManager.getWhitelist();

if (whitelist.isAllowed(onlineProfile)) {
whitelist.remove(onlineProfile);
whitelist.add(new WhitelistEntry(offlineProfile));
try {
whitelist.save();
} catch (IOException e) {
AuthMod.LOGGER.error("Failed to save updated whitelist for username '{}', who disabled online authentication", username, e);
}
}
}
}
}
Loading