From 628389150c150e866d388e3d731090f836655681 Mon Sep 17 00:00:00 2001 From: Hydrogen <1620682458@qq.com> Date: Mon, 18 Aug 2025 02:16:16 +0800 Subject: [PATCH] =?UTF-8?q?fix(token,AxisInnovatorsBox)=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=8A=A5=E9=94=99NullPointerException=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0token=E6=8C=81=E4=B9=85=E5=8C=96=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E5=AF=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- language/saved_language.properties | 2 +- .../innovators/box/AxisInnovatorsBox.java | 26 ++++++++-- .../box/tools/Crypto/AESCryptoUtil.java | 50 +++++++++++++++++++ .../box/tools/Crypto/Base64CryptoUtil.java | 15 ++++++ .../innovators/box/tools/Crypto/HashUtil.java | 12 +++++ .../box/tools/Crypto/WindowsDPAPIUtil.java | 15 ++++++ 6 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/axis/innovators/box/tools/Crypto/AESCryptoUtil.java create mode 100644 src/main/java/com/axis/innovators/box/tools/Crypto/Base64CryptoUtil.java create mode 100644 src/main/java/com/axis/innovators/box/tools/Crypto/HashUtil.java create mode 100644 src/main/java/com/axis/innovators/box/tools/Crypto/WindowsDPAPIUtil.java diff --git a/language/saved_language.properties b/language/saved_language.properties index b822022..ef6cfb5 100644 --- a/language/saved_language.properties +++ b/language/saved_language.properties @@ -1,3 +1,3 @@ #Current Loaded Language -#Sat Aug 16 18:11:03 CST 2025 +#Mon Aug 18 02:11:52 CST 2025 loadedLanguage=system\:zh_CN diff --git a/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java b/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java index a628f50..d508447 100644 --- a/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java +++ b/src/main/java/com/axis/innovators/box/AxisInnovatorsBox.java @@ -12,6 +12,8 @@ import com.axis.innovators.box.register.RegistrationSettingsItem; import com.axis.innovators.box.register.RegistrationTool; import com.axis.innovators.box.register.RegistrationTopic; import com.axis.innovators.box.tools.*; +import com.axis.innovators.box.tools.Crypto.AESCryptoUtil; +import com.axis.innovators.box.tools.Crypto.Base64CryptoUtil; import com.axis.innovators.box.util.PythonResult; import com.axis.innovators.box.util.Tray; import com.axis.innovators.box.verification.LoginResult; @@ -94,14 +96,29 @@ public class AxisInnovatorsBox { (Exception) throwable : new Exception(throwable)); }); // 初始化,这里为了能够在登录窗口使用主题,特意将初始化放在构造函数中 - main.initLog4j2(); - main.setTopic(); + initLog4j2(); + setTopic(); // 加载登录信息,如果没有,弹出登录弹窗,后续可以删掉默认弹出 // TODO: login window should not be show when AxisInnovatorsBox initialize, // it should be show when user click login button. try { StateManager stateManager = new StateManager(); - String token = stateManager.getState("loginToken"); + String excryptedKey = "loginToken"; + try { + excryptedKey = Base64CryptoUtil.base64Encode(excryptedKey); + } catch (Exception e) { + logger.error("Failed to encrypt key", e); + } + String encryptedToken = stateManager.getState(excryptedKey); + String token = null; + if (encryptedToken != null && !encryptedToken.isEmpty()) { + try { + token = AESCryptoUtil.decrypt(encryptedToken); + } catch (Exception ex) { + logger.error("Token 解密失败", ex); + token = null; + } + } if (token == null || token.isEmpty()) { LoginResult loginResult = CasdoorLoginWindow.showLoginDialogAndGetLoginResult(); if (loginResult == null) { @@ -110,7 +127,8 @@ public class AxisInnovatorsBox { JOptionPane.INFORMATION_MESSAGE); } else if (loginResult.success()) { loginData = loginResult.loginData(); - stateManager.saveState("loginToken", loginResult.token()); + String encrypted = AESCryptoUtil.encrypt(loginResult.token()); + stateManager.saveState(excryptedKey, encrypted); logger.info( "Login result: token: " + loginResult.token() + ", user: " + loginResult.user()); JOptionPane.showMessageDialog(null, "登录成功", "登录", diff --git a/src/main/java/com/axis/innovators/box/tools/Crypto/AESCryptoUtil.java b/src/main/java/com/axis/innovators/box/tools/Crypto/AESCryptoUtil.java new file mode 100644 index 0000000..e01cd7a --- /dev/null +++ b/src/main/java/com/axis/innovators/box/tools/Crypto/AESCryptoUtil.java @@ -0,0 +1,50 @@ +package com.axis.innovators.box.tools.Crypto; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import java.nio.file.*; +import java.security.SecureRandom; +import java.util.Base64; + +public class AESCryptoUtil { + private static final String KEY_FILE = System.getProperty("user.home") + "/.lingqi/.axis_box_key"; + + // 获取密钥(Base64字符串,长度16字节) + public static byte[] getKeyBytes() throws Exception { + Path path = Paths.get(KEY_FILE); + if (Files.exists(path)) { + byte[] encrypted = Base64.getDecoder().decode(Files.readAllBytes(path)); + return WindowsDPAPIUtil.unprotect(encrypted); + } else { + // 首次生成密钥 + byte[] keyBytes = new byte[16]; + new SecureRandom().nextBytes(keyBytes); + byte[] encrypted = WindowsDPAPIUtil.protect(keyBytes); + Files.createDirectories(path.getParent()); + Files.write(path, Base64.getEncoder().encode(encrypted)); + return keyBytes; + } + } + + // 加密 + public static String encrypt(String data) throws Exception { + byte[] keyBytes = getKeyBytes(); + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + byte[] encrypted = cipher.doFinal(data.getBytes("UTF-8")); + return Base64.getEncoder().encodeToString(encrypted); + } + + // 解密 + public static String decrypt(String encrypted) throws Exception { + byte[] keyBytes = getKeyBytes(); + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec); + byte[] decoded = Base64.getDecoder().decode(encrypted); + byte[] decrypted = cipher.doFinal(decoded); + return new String(decrypted, "UTF-8"); + } +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/tools/Crypto/Base64CryptoUtil.java b/src/main/java/com/axis/innovators/box/tools/Crypto/Base64CryptoUtil.java new file mode 100644 index 0000000..f16370a --- /dev/null +++ b/src/main/java/com/axis/innovators/box/tools/Crypto/Base64CryptoUtil.java @@ -0,0 +1,15 @@ +package com.axis.innovators.box.tools.Crypto; + +import java.util.Base64; + +public class Base64CryptoUtil { + + public static String base64Encode(String input) { + return Base64.getEncoder().encodeToString(input.getBytes()); + } + + public static String base64Decode(String input) { + byte[] decodedBytes = Base64.getDecoder().decode(input); + return new String(decodedBytes); + } +} diff --git a/src/main/java/com/axis/innovators/box/tools/Crypto/HashUtil.java b/src/main/java/com/axis/innovators/box/tools/Crypto/HashUtil.java new file mode 100644 index 0000000..5b33181 --- /dev/null +++ b/src/main/java/com/axis/innovators/box/tools/Crypto/HashUtil.java @@ -0,0 +1,12 @@ +package com.axis.innovators.box.tools.Crypto; + +import java.security.MessageDigest; +import java.util.Base64; + +public class HashUtil { + public static String sha256(String input) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(input.getBytes("UTF-8")); + return Base64.getEncoder().encodeToString(hash); // 输出为Base64字符串 + } +} diff --git a/src/main/java/com/axis/innovators/box/tools/Crypto/WindowsDPAPIUtil.java b/src/main/java/com/axis/innovators/box/tools/Crypto/WindowsDPAPIUtil.java new file mode 100644 index 0000000..83e4900 --- /dev/null +++ b/src/main/java/com/axis/innovators/box/tools/Crypto/WindowsDPAPIUtil.java @@ -0,0 +1,15 @@ +package com.axis.innovators.box.tools.Crypto; + +import com.sun.jna.platform.win32.Crypt32Util; + +public class WindowsDPAPIUtil { + // 加密 + public static byte[] protect(byte[] data) { + return Crypt32Util.cryptProtectData(data); + } + + // 解密 + public static byte[] unprotect(byte[] encrypted) { + return Crypt32Util.cryptUnprotectData(encrypted); + } +} \ No newline at end of file