Skip to content

Commit

Permalink
Add encryption and confirm screen
Browse files Browse the repository at this point in the history
  • Loading branch information
BuildTools authored and BuildTools committed Sep 14, 2024
1 parent 0cc8cce commit bec19eb
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 8 deletions.
75 changes: 75 additions & 0 deletions src/main/java/me/axieum/mcmod/authme/api/util/EncryptionUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package me.axieum.mcmod.authme.api.util;

import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import me.axieum.mcmod.authme.impl.AuthMe;

public final class EncryptionUtil
{
private static final Cipher CIPHER;

static {
try {
CIPHER = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (Exception e) { // can't happen
throw new RuntimeException(e);
}
}

private EncryptionUtil() {}

/**
* Generates a random 128-bit key.
*
* @return Base64 encoded key
*/
public static String generateKey()
{
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(256);
SecretKey key = keygen.generateKey();
return Base64.getEncoder().encodeToString(key.getEncoded());
} catch (NoSuchAlgorithmException e) { // can't happen
throw new RuntimeException(e);
}
}

public static String decrypt(String b64ciphertext, String b64key)
{
try {
byte[] key = Base64.getDecoder().decode(b64key);
byte[] ciphertext = Base64.getDecoder().decode(b64ciphertext);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(key, 0, 16);
CIPHER.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(CIPHER.doFinal(ciphertext));
} catch (Exception e) {
AuthMe.LOGGER.error("An unexpected error during encryption occurred:");
e.printStackTrace();
return "";
}
}

public static String encrypt(String plaintext, String b64key)
{
try {
byte[] key = Base64.getDecoder().decode(b64key);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(key, 0, 16);
CIPHER.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return Base64.getEncoder().encodeToString(CIPHER.doFinal(plaintext.getBytes()));
} catch (Exception e) {
AuthMe.LOGGER.error("An unexpected error during decryption occurred:");
e.printStackTrace();
return "";
}
}
}
21 changes: 15 additions & 6 deletions src/main/java/me/axieum/mcmod/authme/impl/config/AuthMeConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;

import me.axieum.mcmod.authme.api.util.EncryptionUtil;
import me.axieum.mcmod.authme.api.util.MicrosoftUtils;
import me.axieum.mcmod.authme.api.util.MicrosoftUtils.MicrosoftPrompt;

Expand Down Expand Up @@ -47,12 +48,16 @@ public static class AuthButtonSchema
*/
public static class AutoLoginSchema
{
@Comment("Save session after login to be used for auto login")
@Comment("Save session after login to disc to be reused.")
public boolean saveSession = false;

@Comment("Automatically attempt to login using a saved session")
public boolean doAutoLogin = false;

@Comment("Whether the warning screen has been confirmed")
@ConfigEntry.Gui.Excluded
public boolean warningScreenConfirmed = false;

@Comment("Saved session (valid for 24h if account type is msa - Microsoft)")
@ConfigEntry.Gui.CollapsibleObject()
public SavedSessionSchema savedSession = new SavedSessionSchema();
Expand All @@ -63,10 +68,13 @@ public static class SavedSessionSchema
public String username = "";
@Comment("Player UUID")
public String uuid = "";
@ConfigEntry.Gui.Excluded
@Comment("Access Token - DO NOT SHARE")
@ConfigEntry.Gui.Excluded // hide option from config screen
@Comment("Encrypted Access Token - DO NOT SHARE WITH ANYONE")
public String accessToken = "";
@ConfigEntry.Gui.Excluded
@Comment("Encryption key - DO NOT SHARE WITH ANYONE")
public String encryptionKey = "";
@ConfigEntry.Gui.Excluded
public String xuid = "";
@ConfigEntry.Gui.Excluded
public String clientId = "";
Expand All @@ -75,15 +83,15 @@ public static class SavedSessionSchema

public boolean hasSavedSession()
{
return !(username.isEmpty() || uuid.isEmpty() || accessToken.isEmpty()
return !(username.isEmpty() || uuid.isEmpty() || accessToken.isEmpty() || encryptionKey.isEmpty()
|| Session.AccountType.byName(accountType) == null);
}

public Session getSession()
{
return new Session(username,
uuid,
accessToken,
EncryptionUtil.decrypt(accessToken, encryptionKey),
xuid.isEmpty() ? Optional.empty() : Optional.of(xuid),
clientId.isEmpty() ? Optional.empty() : Optional.of(clientId),
Session.AccountType.byName(accountType));
Expand All @@ -93,7 +101,8 @@ public void setSession(Session session)
{
username = session.getUsername();
uuid = session.getUuid();
accessToken = session.getAccessToken();
encryptionKey = EncryptionUtil.generateKey();
accessToken = EncryptionUtil.encrypt(session.getAccessToken(), encryptionKey);
xuid = session.getXuid().orElse("");
clientId = session.getClientId().orElse("");
accountType = session.getAccountType().getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import me.axieum.mcmod.authme.api.util.SessionUtils;
import me.axieum.mcmod.authme.impl.AuthMe;
import me.axieum.mcmod.authme.impl.config.AuthMeConfig;
import static me.axieum.mcmod.authme.impl.AuthMe.CONFIG;
import static me.axieum.mcmod.authme.impl.AuthMe.WIDGETS_TEXTURE;
import static me.axieum.mcmod.authme.impl.AuthMe.getConfig;

/**
Expand Down Expand Up @@ -94,11 +97,17 @@ protected void init()
client.getWindow().getHandle(), InputUtil.GLFW_KEY_LEFT_CONTROL
);
if (getConfig().methods.microsoft.isDefaults()) {
client.setScreen(new MicrosoftAuthScreen(this, parentScreen, selectAccount));
saveSessionWarning(new MicrosoftAuthScreen(this, parentScreen, selectAccount));
} else {
AuthMe.LOGGER.warn("Non-default Microsoft authentication URLs are in use!");
ConfirmScreen confirmScreen = new ConfirmScreen(
a -> client.setScreen(a ? new MicrosoftAuthScreen(this, parentScreen, selectAccount) : this),
accepted -> {
if (accepted) {
saveSessionWarning(new MicrosoftAuthScreen(this, parentScreen, selectAccount));
} else {
client.setScreen(this);
}
},
Text.translatable("gui.authme.microsoft.warning.title"),
Text.translatable("gui.authme.microsoft.warning.body"),
Text.translatable("gui.authme.microsoft.warning.accept"),
Expand Down Expand Up @@ -175,4 +184,31 @@ public void close()
{
if (client != null) client.setScreen(parentScreen);
}

public void saveSessionWarning(Screen nextScreen)
{
assert client != null;
AuthMeConfig.AutoLoginSchema autoLogin = getConfig().autoLogin;
if (autoLogin.saveSession && !autoLogin.warningScreenConfirmed) {
ConfirmScreen confirmScreen = new ConfirmScreen(
accepted -> {
if (accepted) {
client.setScreen(nextScreen);
autoLogin.warningScreenConfirmed = true;
CONFIG.save();
} else {
client.setScreen(this);
}
},
Text.translatable("gui.authme.autoLogin.warning.title"),
Text.translatable("gui.authme.autoLogin.warning.body"),
Text.translatable("gui.authme.autoLogin.warning.accept"),
Text.translatable("gui.authme.autoLogin.warning.cancel")
);
client.setScreen(confirmScreen);
confirmScreen.disableButtons(40);
} else {
client.setScreen(nextScreen);
}
}
}
5 changes: 5 additions & 0 deletions src/main/resources/assets/authme/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
"gui.authme.microsoft.warning.accept": "I know what I'm doing",
"gui.authme.microsoft.warning.cancel": "Back to safety",

"gui.authme.autoLogin.warning.title": "Warning! Session will be saved to disk after login",
"gui.authme.autoLogin.warning.body": "Your access token, which is used for logging into your account and is valid for 24h, will be stored on your device's disk after you log in. Use at your own risk!",
"gui.authme.autoLogin.warning.accept": "I understand",
"gui.authme.autoLogin.warning.cancel": "Back",

"gui.authme.mojang.title": "Login via Mojang (Legacy)",

"gui.authme.offline.title": "Login Offline",
Expand Down

0 comments on commit bec19eb

Please sign in to comment.